001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.hdfs.server.namenode; 020 021import java.text.NumberFormat; 022import java.util.Arrays; 023import java.util.Collections; 024import java.util.Comparator; 025import java.util.EnumMap; 026import java.util.Formatter; 027import java.util.HashMap; 028import java.util.LinkedList; 029import java.util.List; 030import java.util.Map; 031import java.util.Map.Entry; 032import java.util.Objects; 033 034import org.apache.hadoop.fs.StorageType; 035import org.apache.hadoop.hdfs.protocol.BlockStoragePolicy; 036 037/** 038 * Aggregate the storage type information for a set of blocks 039 * 040 */ 041public class StoragePolicySummary { 042 043 Map<StorageTypeAllocation, Long> storageComboCounts = new HashMap<>(); 044 final BlockStoragePolicy[] storagePolicies; 045 int totalBlocks; 046 047 StoragePolicySummary(BlockStoragePolicy[] storagePolicies) { 048 this.storagePolicies = storagePolicies; 049 } 050 051 // Add a storage type combination 052 void add(StorageType[] storageTypes, BlockStoragePolicy policy) { 053 StorageTypeAllocation storageCombo = 054 new StorageTypeAllocation(storageTypes, policy); 055 Long count = storageComboCounts.get(storageCombo); 056 if (count == null) { 057 storageComboCounts.put(storageCombo, 1l); 058 storageCombo.setActualStoragePolicy( 059 getStoragePolicy(storageCombo.getStorageTypes())); 060 } else { 061 storageComboCounts.put(storageCombo, count.longValue()+1); 062 } 063 totalBlocks++; 064 } 065 066 // sort the storageType combinations based on the total blocks counts 067 // in descending order 068 static List<Entry<StorageTypeAllocation, Long>> sortByComparator( 069 Map<StorageTypeAllocation, Long> unsortMap) { 070 List<Entry<StorageTypeAllocation, Long>> storageAllocations = 071 new LinkedList<>(unsortMap.entrySet()); 072 // Sorting the list based on values 073 Collections.sort(storageAllocations, 074 new Comparator<Entry<StorageTypeAllocation, Long>>() { 075 public int compare(Entry<StorageTypeAllocation, Long> o1, 076 Entry<StorageTypeAllocation, Long> o2) 077 { 078 return o2.getValue().compareTo(o1.getValue()); 079 } 080 }); 081 return storageAllocations; 082 } 083 084 public String toString() { 085 StringBuilder compliantBlocksSB = new StringBuilder(); 086 compliantBlocksSB.append("\nBlocks satisfying the specified storage policy:"); 087 compliantBlocksSB.append("\nStorage Policy # of blocks % of blocks\n"); 088 StringBuilder nonCompliantBlocksSB = new StringBuilder(); 089 Formatter compliantFormatter = new Formatter(compliantBlocksSB); 090 Formatter nonCompliantFormatter = new Formatter(nonCompliantBlocksSB); 091 NumberFormat percentFormat = NumberFormat.getPercentInstance(); 092 percentFormat.setMinimumFractionDigits(4); 093 percentFormat.setMaximumFractionDigits(4); 094 for (Map.Entry<StorageTypeAllocation, Long> storageComboCount: 095 sortByComparator(storageComboCounts)) { 096 double percent = (double) storageComboCount.getValue() / 097 (double) totalBlocks; 098 StorageTypeAllocation sta = storageComboCount.getKey(); 099 if (sta.policyMatches()) { 100 compliantFormatter.format("%-25s %10d %20s%n", 101 sta.getStoragePolicyDescriptor(), 102 storageComboCount.getValue(), 103 percentFormat.format(percent)); 104 } else { 105 if (nonCompliantBlocksSB.length() == 0) { 106 nonCompliantBlocksSB.append("\nBlocks NOT satisfying the specified storage policy:"); 107 nonCompliantBlocksSB.append("\nStorage Policy "); 108 nonCompliantBlocksSB.append( 109 "Specified Storage Policy # of blocks % of blocks\n"); 110 } 111 nonCompliantFormatter.format("%-35s %-20s %10d %20s%n", 112 sta.getStoragePolicyDescriptor(), 113 sta.getSpecifiedStoragePolicy().getName(), 114 storageComboCount.getValue(), 115 percentFormat.format(percent)); 116 } 117 } 118 if (nonCompliantBlocksSB.length() == 0) { 119 nonCompliantBlocksSB.append("\nAll blocks satisfy specified storage policy.\n"); 120 } 121 compliantFormatter.close(); 122 nonCompliantFormatter.close(); 123 return compliantBlocksSB.toString() + nonCompliantBlocksSB; 124 } 125 126 /** 127 * 128 * @param storageTypes - sorted array of storageTypes 129 * @return Storage Policy which matches the specific storage Combination 130 */ 131 private BlockStoragePolicy getStoragePolicy(StorageType[] storageTypes) { 132 for (BlockStoragePolicy storagePolicy:storagePolicies) { 133 StorageType[] policyStorageTypes = storagePolicy.getStorageTypes(); 134 policyStorageTypes = Arrays.copyOf(policyStorageTypes, policyStorageTypes.length); 135 Arrays.sort(policyStorageTypes); 136 if (policyStorageTypes.length <= storageTypes.length) { 137 int i = 0; 138 for (; i < policyStorageTypes.length; i++) { 139 if (policyStorageTypes[i] != storageTypes[i]) { 140 break; 141 } 142 } 143 if (i < policyStorageTypes.length) { 144 continue; 145 } 146 int j=policyStorageTypes.length; 147 for (; j < storageTypes.length; j++) { 148 if (policyStorageTypes[i-1] != storageTypes[j]) { 149 break; 150 } 151 } 152 153 if (j==storageTypes.length) { 154 return storagePolicy; 155 } 156 } 157 } 158 return null; 159 } 160 161 /** 162 * Internal class which represents a unique Storage type combination 163 * 164 */ 165 static class StorageTypeAllocation { 166 private final BlockStoragePolicy specifiedStoragePolicy; 167 private final StorageType[] storageTypes; 168 private BlockStoragePolicy actualStoragePolicy; 169 170 StorageTypeAllocation(StorageType[] storageTypes, 171 BlockStoragePolicy specifiedStoragePolicy) { 172 Arrays.sort(storageTypes); 173 this.storageTypes = storageTypes; 174 this.specifiedStoragePolicy = specifiedStoragePolicy; 175 } 176 177 StorageType[] getStorageTypes() { 178 return storageTypes; 179 } 180 181 BlockStoragePolicy getSpecifiedStoragePolicy() { 182 return specifiedStoragePolicy; 183 } 184 185 void setActualStoragePolicy(BlockStoragePolicy actualStoragePolicy) { 186 this.actualStoragePolicy = actualStoragePolicy; 187 } 188 189 BlockStoragePolicy getActualStoragePolicy() { 190 return actualStoragePolicy; 191 } 192 193 private static String getStorageAllocationAsString 194 (Map<StorageType, Integer> storageType_countmap) { 195 StringBuilder sb = new StringBuilder(); 196 for (Map.Entry<StorageType, Integer> 197 storageTypeCountEntry:storageType_countmap.entrySet()) { 198 sb.append(storageTypeCountEntry.getKey().name()+ ":" 199 + storageTypeCountEntry.getValue() + ","); 200 } 201 if (sb.length() > 1) { 202 sb.deleteCharAt(sb.length()-1); 203 } 204 return sb.toString(); 205 } 206 207 private String getStorageAllocationAsString() { 208 Map<StorageType, Integer> storageType_countmap = 209 new EnumMap<>(StorageType.class); 210 for (StorageType storageType: storageTypes) { 211 Integer count = storageType_countmap.get(storageType); 212 if (count == null) { 213 storageType_countmap.put(storageType, 1); 214 } else { 215 storageType_countmap.put(storageType, count.intValue()+1); 216 } 217 } 218 return (getStorageAllocationAsString(storageType_countmap)); 219 } 220 221 String getStoragePolicyDescriptor() { 222 StringBuilder storagePolicyDescriptorSB = new StringBuilder(); 223 if (actualStoragePolicy!=null) { 224 storagePolicyDescriptorSB.append(getStorageAllocationAsString()) 225 .append("(") 226 .append(actualStoragePolicy.getName()) 227 .append(")"); 228 } else { 229 storagePolicyDescriptorSB.append(getStorageAllocationAsString()); 230 } 231 return storagePolicyDescriptorSB.toString(); 232 } 233 234 boolean policyMatches() { 235 return specifiedStoragePolicy.equals(actualStoragePolicy); 236 } 237 238 @Override 239 public String toString() { 240 return specifiedStoragePolicy.getName() + "|" + getStoragePolicyDescriptor(); 241 } 242 243 @Override 244 public int hashCode() { 245 return Objects.hash(specifiedStoragePolicy,Arrays.hashCode(storageTypes)); 246 } 247 248 @Override 249 public boolean equals(Object another) { 250 return (another instanceof StorageTypeAllocation && 251 Objects.equals(specifiedStoragePolicy, 252 ((StorageTypeAllocation)another).specifiedStoragePolicy) && 253 Arrays.equals(storageTypes, 254 ((StorageTypeAllocation)another).storageTypes)); 255 } 256 } 257}