blob: bcdad355ac54f2ba9c9374fc96470a4e877f288a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.server.namenode;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.Formatter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdfs.protocol.BlockStoragePolicy;
/**
* Aggregate the storage type information for a set of blocks
*
*/
public class StoragePolicySummary {
Map<StorageTypeAllocation, Long> storageComboCounts = new HashMap<>();
final BlockStoragePolicy[] storagePolicies;
int totalBlocks;
StoragePolicySummary(BlockStoragePolicy[] storagePolicies) {
this.storagePolicies = storagePolicies;
}
// Add a storage type combination
void add(StorageType[] storageTypes, BlockStoragePolicy policy) {
StorageTypeAllocation storageCombo =
new StorageTypeAllocation(storageTypes, policy);
Long count = storageComboCounts.get(storageCombo);
if (count == null) {
storageComboCounts.put(storageCombo, 1l);
storageCombo.setActualStoragePolicy(
getStoragePolicy(storageCombo.getStorageTypes()));
} else {
storageComboCounts.put(storageCombo, count.longValue()+1);
}
totalBlocks++;
}
// sort the storageType combinations based on the total blocks counts
// in descending order
static List<Entry<StorageTypeAllocation, Long>> sortByComparator(
Map<StorageTypeAllocation, Long> unsortMap) {
List<Entry<StorageTypeAllocation, Long>> storageAllocations =
new LinkedList<>(unsortMap.entrySet());
// Sorting the list based on values
Collections.sort(storageAllocations,
new Comparator<Entry<StorageTypeAllocation, Long>>() {
public int compare(Entry<StorageTypeAllocation, Long> o1,
Entry<StorageTypeAllocation, Long> o2)
{
return o2.getValue().compareTo(o1.getValue());
}
});
return storageAllocations;
}
public String toString() {
StringBuilder compliantBlocksSB = new StringBuilder();
compliantBlocksSB.append("\nBlocks satisfying the specified storage policy:");
compliantBlocksSB.append("\nStorage Policy # of blocks % of blocks\n");
StringBuilder nonCompliantBlocksSB = new StringBuilder();
Formatter compliantFormatter = new Formatter(compliantBlocksSB);
Formatter nonCompliantFormatter = new Formatter(nonCompliantBlocksSB);
NumberFormat percentFormat = NumberFormat.getPercentInstance();
percentFormat.setMinimumFractionDigits(4);
percentFormat.setMaximumFractionDigits(4);
for (Map.Entry<StorageTypeAllocation, Long> storageComboCount:
sortByComparator(storageComboCounts)) {
double percent = (double) storageComboCount.getValue() /
(double) totalBlocks;
StorageTypeAllocation sta = storageComboCount.getKey();
if (sta.policyMatches()) {
compliantFormatter.format("%-25s %10d %20s%n",
sta.getStoragePolicyDescriptor(),
storageComboCount.getValue(),
percentFormat.format(percent));
} else {
if (nonCompliantBlocksSB.length() == 0) {
nonCompliantBlocksSB.append("\nBlocks NOT satisfying the specified storage policy:");
nonCompliantBlocksSB.append("\nStorage Policy ");
nonCompliantBlocksSB.append(
"Specified Storage Policy # of blocks % of blocks\n");
}
nonCompliantFormatter.format("%-35s %-20s %10d %20s%n",
sta.getStoragePolicyDescriptor(),
sta.getSpecifiedStoragePolicy().getName(),
storageComboCount.getValue(),
percentFormat.format(percent));
}
}
if (nonCompliantBlocksSB.length() == 0) {
nonCompliantBlocksSB.append("\nAll blocks satisfy specified storage policy.\n");
}
compliantFormatter.close();
nonCompliantFormatter.close();
return compliantBlocksSB.toString() + nonCompliantBlocksSB;
}
/**
*
* @param storageTypes - sorted array of storageTypes
* @return Storage Policy which matches the specific storage Combination
*/
private BlockStoragePolicy getStoragePolicy(StorageType[] storageTypes) {
for (BlockStoragePolicy storagePolicy:storagePolicies) {
StorageType[] policyStorageTypes = storagePolicy.getStorageTypes();
policyStorageTypes = Arrays.copyOf(policyStorageTypes, policyStorageTypes.length);
Arrays.sort(policyStorageTypes);
if (policyStorageTypes.length <= storageTypes.length) {
int i = 0;
for (; i < policyStorageTypes.length; i++) {
if (policyStorageTypes[i] != storageTypes[i]) {
break;
}
}
if (i < policyStorageTypes.length) {
continue;
}
int j=policyStorageTypes.length;
for (; j < storageTypes.length; j++) {
if (policyStorageTypes[i-1] != storageTypes[j]) {
break;
}
}
if (j==storageTypes.length) {
return storagePolicy;
}
}
}
return null;
}
/**
* Internal class which represents a unique Storage type combination
*
*/
static class StorageTypeAllocation {
private final BlockStoragePolicy specifiedStoragePolicy;
private final StorageType[] storageTypes;
private BlockStoragePolicy actualStoragePolicy;
StorageTypeAllocation(StorageType[] storageTypes,
BlockStoragePolicy specifiedStoragePolicy) {
Arrays.sort(storageTypes);
this.storageTypes = storageTypes;
this.specifiedStoragePolicy = specifiedStoragePolicy;
}
StorageType[] getStorageTypes() {
return storageTypes;
}
BlockStoragePolicy getSpecifiedStoragePolicy() {
return specifiedStoragePolicy;
}
void setActualStoragePolicy(BlockStoragePolicy actualStoragePolicy) {
this.actualStoragePolicy = actualStoragePolicy;
}
BlockStoragePolicy getActualStoragePolicy() {
return actualStoragePolicy;
}
private static String getStorageAllocationAsString
(Map<StorageType, Integer> storageType_countmap) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<StorageType, Integer>
storageTypeCountEntry:storageType_countmap.entrySet()) {
sb.append(storageTypeCountEntry.getKey().name()+ ":"
+ storageTypeCountEntry.getValue() + ",");
}
if (sb.length() > 1) {
sb.deleteCharAt(sb.length()-1);
}
return sb.toString();
}
private String getStorageAllocationAsString() {
Map<StorageType, Integer> storageType_countmap =
new EnumMap<>(StorageType.class);
for (StorageType storageType: storageTypes) {
Integer count = storageType_countmap.get(storageType);
if (count == null) {
storageType_countmap.put(storageType, 1);
} else {
storageType_countmap.put(storageType, count.intValue()+1);
}
}
return (getStorageAllocationAsString(storageType_countmap));
}
String getStoragePolicyDescriptor() {
StringBuilder storagePolicyDescriptorSB = new StringBuilder();
if (actualStoragePolicy!=null) {
storagePolicyDescriptorSB.append(getStorageAllocationAsString())
.append("(")
.append(actualStoragePolicy.getName())
.append(")");
} else {
storagePolicyDescriptorSB.append(getStorageAllocationAsString());
}
return storagePolicyDescriptorSB.toString();
}
boolean policyMatches() {
return specifiedStoragePolicy.equals(actualStoragePolicy);
}
@Override
public String toString() {
return specifiedStoragePolicy.getName() + "|" + getStoragePolicyDescriptor();
}
@Override
public int hashCode() {
return Objects.hash(specifiedStoragePolicy,Arrays.hashCode(storageTypes));
}
@Override
public boolean equals(Object another) {
return (another instanceof StorageTypeAllocation &&
Objects.equals(specifiedStoragePolicy,
((StorageTypeAllocation)another).specifiedStoragePolicy) &&
Arrays.equals(storageTypes,
((StorageTypeAllocation)another).storageTypes));
}
}
}