1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.master;
20
21 import java.text.DecimalFormat;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.hadoop.hbase.classification.InterfaceAudience;
32 import org.apache.hadoop.hbase.HRegionInfo;
33 import org.apache.hadoop.hbase.ServerName;
34 import org.apache.hadoop.hbase.TableName;
35 import org.apache.hadoop.hbase.master.balancer.FavoredNodeAssignmentHelper;
36 import org.apache.hadoop.hbase.master.balancer.FavoredNodesPlan;
37
38
39
40
41
42 @InterfaceAudience.Private
43 public class AssignmentVerificationReport {
44 private static final Log LOG = LogFactory.getLog(
45 AssignmentVerificationReport.class.getName());
46
47 private TableName tableName = null;
48 private boolean enforceLocality = false;
49 private boolean isFilledUp = false;
50
51 private int totalRegions = 0;
52 private int totalRegionServers = 0;
53
54 private List<HRegionInfo> unAssignedRegionsList =
55 new ArrayList<HRegionInfo>();
56
57
58 private List<HRegionInfo> regionsWithoutValidFavoredNodes =
59 new ArrayList<HRegionInfo>();
60
61
62 private List<HRegionInfo> nonFavoredAssignedRegionList =
63 new ArrayList<HRegionInfo>();
64
65
66 private int totalFavoredAssignments = 0;
67 private int[] favoredNodes = new int[FavoredNodeAssignmentHelper.FAVORED_NODES_NUM];
68 private float[] favoredNodesLocalitySummary =
69 new float[FavoredNodeAssignmentHelper.FAVORED_NODES_NUM];
70 private float actualLocalitySummary = 0;
71
72
73 private float avgRegionsOnRS = 0;
74 private int maxRegionsOnRS = 0;
75 private int minRegionsOnRS = Integer.MAX_VALUE;
76 private Set<ServerName> mostLoadedRSSet =
77 new HashSet<ServerName>();
78 private Set<ServerName> leastLoadedRSSet =
79 new HashSet<ServerName>();
80
81 private float avgDispersionScore = 0;
82 private float maxDispersionScore = 0;
83 private Set<ServerName> maxDispersionScoreServerSet =
84 new HashSet<ServerName>();
85 private float minDispersionScore = Float.MAX_VALUE;
86 private Set<ServerName> minDispersionScoreServerSet =
87 new HashSet<ServerName>();
88
89 private float avgDispersionNum = 0;
90 private float maxDispersionNum = 0;
91 private Set<ServerName> maxDispersionNumServerSet =
92 new HashSet<ServerName>();
93 private float minDispersionNum = Float.MAX_VALUE;
94 private Set<ServerName> minDispersionNumServerSet =
95 new HashSet<ServerName>();
96
97 public void fillUp(TableName tableName, SnapshotOfRegionAssignmentFromMeta snapshot,
98 Map<String, Map<String, Float>> regionLocalityMap) {
99
100 this.tableName = tableName;
101
102
103 List<HRegionInfo> regionInfoList =
104 snapshot.getTableToRegionMap().get(tableName);
105
106 this.totalRegions = regionInfoList.size();
107
108
109 FavoredNodesPlan favoredNodesAssignment = snapshot.getExistingAssignmentPlan();
110
111 Map<HRegionInfo, ServerName> currentAssignment =
112 snapshot.getRegionToRegionServerMap();
113
114 Map<ServerName, Integer> serverToHostingRegionCounterMap =
115 new HashMap<ServerName, Integer>();
116
117 Map<ServerName, Integer> primaryRSToRegionCounterMap =
118 new HashMap<ServerName, Integer>();
119 Map<ServerName, Set<ServerName>> primaryToSecTerRSMap =
120 new HashMap<ServerName, Set<ServerName>>();
121
122
123
124 for (HRegionInfo region : regionInfoList) {
125 try {
126 ServerName currentRS = currentAssignment.get(region);
127
128 if (currentRS == null) {
129 unAssignedRegionsList.add(region);
130 continue;
131 }
132
133
134 Integer hostRegionCounter = serverToHostingRegionCounterMap.get(currentRS);
135 if (hostRegionCounter == null) {
136 hostRegionCounter = Integer.valueOf(0);
137 }
138 hostRegionCounter = hostRegionCounter.intValue() + 1;
139 serverToHostingRegionCounterMap.put(currentRS, hostRegionCounter);
140
141
142 List<ServerName> favoredNodes = favoredNodesAssignment.getFavoredNodes(region);
143 if (favoredNodes == null ||
144 favoredNodes.size() != FavoredNodeAssignmentHelper.FAVORED_NODES_NUM) {
145 regionsWithoutValidFavoredNodes.add(region);
146 continue;
147 }
148
149 ServerName primaryRS =
150 favoredNodes.get(FavoredNodesPlan.Position.PRIMARY.ordinal());
151 ServerName secondaryRS =
152 favoredNodes.get(FavoredNodesPlan.Position.SECONDARY.ordinal());
153 ServerName tertiaryRS =
154 favoredNodes.get(FavoredNodesPlan.Position.TERTIARY.ordinal());
155
156
157 Integer regionCounter = primaryRSToRegionCounterMap.get(primaryRS);
158 if (regionCounter == null) {
159 regionCounter = Integer.valueOf(0);
160 }
161 regionCounter = regionCounter.intValue() + 1;
162 primaryRSToRegionCounterMap.put(primaryRS, regionCounter);
163
164
165 Set<ServerName> secAndTerSet = primaryToSecTerRSMap.get(primaryRS);
166 if (secAndTerSet == null) {
167 secAndTerSet = new HashSet<ServerName>();
168 }
169 secAndTerSet.add(secondaryRS);
170 secAndTerSet.add(tertiaryRS);
171 primaryToSecTerRSMap.put(primaryRS, secAndTerSet);
172
173
174 FavoredNodesPlan.Position favoredNodePosition =
175 FavoredNodesPlan.getFavoredServerPosition(favoredNodes, currentRS);
176
177
178 if (favoredNodePosition == null) {
179 nonFavoredAssignedRegionList.add(region);
180 continue;
181 }
182
183 this.favoredNodes[favoredNodePosition.ordinal()]++;
184 totalFavoredAssignments++;
185
186
187 if (regionLocalityMap != null) {
188
189 this.enforceLocality = true;
190
191
192 Map<String, Float> regionDegreeLocalityMap =
193 regionLocalityMap.get(region.getEncodedName());
194 if (regionDegreeLocalityMap == null) {
195 continue;
196 }
197
198
199 for (FavoredNodesPlan.Position p : FavoredNodesPlan.Position.values()) {
200 ServerName favoredNode = favoredNodes.get(p.ordinal());
201
202 Float locality =
203 regionDegreeLocalityMap.get(favoredNode.getHostname());
204 if (locality != null) {
205 this.favoredNodesLocalitySummary[p.ordinal()] += locality;
206 }
207 }
208
209
210 Float actualLocality =
211 regionDegreeLocalityMap.get(currentRS.getHostname());
212 if (actualLocality != null) {
213 this.actualLocalitySummary += actualLocality;
214 }
215 }
216 } catch (Exception e) {
217 LOG.error("Cannot verify the region assignment for region " +
218 ((region == null) ? " null " : region.getRegionNameAsString()) +
219 "because of " + e);
220 }
221 }
222
223 float dispersionScoreSummary = 0;
224 float dispersionNumSummary = 0;
225
226 for (Map.Entry<ServerName, Integer> entry :
227 primaryRSToRegionCounterMap.entrySet()) {
228 ServerName primaryRS = entry.getKey();
229 Integer regionsOnPrimary = entry.getValue();
230
231
232 float dispersionScore = 0;
233 int dispersionNum = 0;
234 if (primaryToSecTerRSMap.get(primaryRS) != null
235 && regionsOnPrimary.intValue() != 0) {
236 dispersionNum = primaryToSecTerRSMap.get(primaryRS).size();
237 dispersionScore = dispersionNum /
238 ((float) regionsOnPrimary.intValue() * 2);
239 }
240
241 if (dispersionScore > this.maxDispersionScore) {
242 this.maxDispersionScoreServerSet.clear();
243 this.maxDispersionScoreServerSet.add(primaryRS);
244 this.maxDispersionScore = dispersionScore;
245 } else if (dispersionScore == this.maxDispersionScore) {
246 this.maxDispersionScoreServerSet.add(primaryRS);
247 }
248
249
250 if (dispersionNum > this.maxDispersionNum) {
251 this.maxDispersionNumServerSet.clear();
252 this.maxDispersionNumServerSet.add(primaryRS);
253 this.maxDispersionNum = dispersionNum;
254 } else if (dispersionNum == this.maxDispersionNum) {
255 this.maxDispersionNumServerSet.add(primaryRS);
256 }
257
258
259 if (dispersionScore < this.minDispersionScore) {
260 this.minDispersionScoreServerSet.clear();
261 this.minDispersionScoreServerSet.add(primaryRS);
262 this.minDispersionScore = dispersionScore;
263 } else if (dispersionScore == this.minDispersionScore) {
264 this.minDispersionScoreServerSet.add(primaryRS);
265 }
266
267
268 if (dispersionNum < this.minDispersionNum) {
269 this.minDispersionNumServerSet.clear();
270 this.minDispersionNumServerSet.add(primaryRS);
271 this.minDispersionNum = dispersionNum;
272 } else if (dispersionNum == this.minDispersionNum) {
273 this.minDispersionNumServerSet.add(primaryRS);
274 }
275
276 dispersionScoreSummary += dispersionScore;
277 dispersionNumSummary += dispersionNum;
278 }
279
280
281 if (primaryRSToRegionCounterMap.keySet().size() != 0) {
282 this.avgDispersionScore = dispersionScoreSummary /
283 (float) primaryRSToRegionCounterMap.keySet().size();
284 this.avgDispersionNum = dispersionNumSummary /
285 (float) primaryRSToRegionCounterMap.keySet().size();
286 }
287
288
289 for (Map.Entry<ServerName, Integer> entry :
290 serverToHostingRegionCounterMap.entrySet()) {
291 ServerName currentRS = entry.getKey();
292 int hostRegionCounter = entry.getValue().intValue();
293
294
295 if (hostRegionCounter > this.maxRegionsOnRS) {
296 maxRegionsOnRS = hostRegionCounter;
297 this.mostLoadedRSSet.clear();
298 this.mostLoadedRSSet.add(currentRS);
299 } else if (hostRegionCounter == this.maxRegionsOnRS) {
300 this.mostLoadedRSSet.add(currentRS);
301 }
302
303
304 if (hostRegionCounter < this.minRegionsOnRS) {
305 this.minRegionsOnRS = hostRegionCounter;
306 this.leastLoadedRSSet.clear();
307 this.leastLoadedRSSet.add(currentRS);
308 } else if (hostRegionCounter == this.minRegionsOnRS) {
309 this.leastLoadedRSSet.add(currentRS);
310 }
311 }
312
313
314 this.totalRegionServers = serverToHostingRegionCounterMap.keySet().size();
315 this.avgRegionsOnRS = (totalRegionServers == 0) ? 0 :
316 (totalRegions / (float) totalRegionServers);
317
318 isFilledUp = true;
319 }
320
321
322
323
324
325
326
327 public void fillUpDispersion(TableName tableName,
328 SnapshotOfRegionAssignmentFromMeta snapshot, FavoredNodesPlan newPlan) {
329
330 this.tableName = tableName;
331
332 List<HRegionInfo> regionInfoList = snapshot.getTableToRegionMap().get(
333 tableName);
334
335 this.totalRegions = regionInfoList.size();
336 FavoredNodesPlan plan = null;
337 if (newPlan == null) {
338 plan = snapshot.getExistingAssignmentPlan();
339 } else {
340 plan = newPlan;
341 }
342
343 Map<ServerName, Integer> primaryRSToRegionCounterMap =
344 new HashMap<ServerName, Integer>();
345 Map<ServerName, Set<ServerName>> primaryToSecTerRSMap =
346 new HashMap<ServerName, Set<ServerName>>();
347
348
349
350 for (HRegionInfo region : regionInfoList) {
351 try {
352
353 List<ServerName> favoredNodes = plan.getFavoredNodes(region);
354 if (favoredNodes == null
355 || favoredNodes.size() != FavoredNodeAssignmentHelper.FAVORED_NODES_NUM) {
356 regionsWithoutValidFavoredNodes.add(region);
357 continue;
358 }
359
360 ServerName primaryRS = favoredNodes
361 .get(FavoredNodesPlan.Position.PRIMARY.ordinal());
362 ServerName secondaryRS = favoredNodes
363 .get(FavoredNodesPlan.Position.SECONDARY.ordinal());
364 ServerName tertiaryRS = favoredNodes
365 .get(FavoredNodesPlan.Position.TERTIARY.ordinal());
366
367
368 Integer regionCounter = primaryRSToRegionCounterMap.get(primaryRS);
369 if (regionCounter == null) {
370 regionCounter = Integer.valueOf(0);
371 }
372 regionCounter = regionCounter.intValue() + 1;
373 primaryRSToRegionCounterMap.put(primaryRS, regionCounter);
374
375
376 Set<ServerName> secAndTerSet = primaryToSecTerRSMap.get(primaryRS);
377 if (secAndTerSet == null) {
378 secAndTerSet = new HashSet<ServerName>();
379 }
380 secAndTerSet.add(secondaryRS);
381 secAndTerSet.add(tertiaryRS);
382 primaryToSecTerRSMap.put(primaryRS, secAndTerSet);
383 } catch (Exception e) {
384 LOG.error("Cannot verify the region assignment for region "
385 + ((region == null) ? " null " : region.getRegionNameAsString())
386 + "because of " + e);
387 }
388 }
389 float dispersionScoreSummary = 0;
390 float dispersionNumSummary = 0;
391
392 for (Map.Entry<ServerName, Integer> entry :
393 primaryRSToRegionCounterMap.entrySet()) {
394 ServerName primaryRS = entry.getKey();
395 Integer regionsOnPrimary = entry.getValue();
396
397
398 float dispersionScore = 0;
399 int dispersionNum = 0;
400 if (primaryToSecTerRSMap.get(primaryRS) != null
401 && regionsOnPrimary.intValue() != 0) {
402 dispersionNum = primaryToSecTerRSMap.get(primaryRS).size();
403 dispersionScore = dispersionNum /
404 ((float) regionsOnPrimary.intValue() * 2);
405 }
406
407
408 if (dispersionNum > this.maxDispersionNum) {
409 this.maxDispersionNumServerSet.clear();
410 this.maxDispersionNumServerSet.add(primaryRS);
411 this.maxDispersionNum = dispersionNum;
412 } else if (dispersionNum == this.maxDispersionNum) {
413 this.maxDispersionNumServerSet.add(primaryRS);
414 }
415
416
417 if (dispersionScore < this.minDispersionScore) {
418 this.minDispersionScoreServerSet.clear();
419 this.minDispersionScoreServerSet.add(primaryRS);
420 this.minDispersionScore = dispersionScore;
421 } else if (dispersionScore == this.minDispersionScore) {
422 this.minDispersionScoreServerSet.add(primaryRS);
423 }
424
425
426 if (dispersionNum < this.minDispersionNum) {
427 this.minDispersionNumServerSet.clear();
428 this.minDispersionNumServerSet.add(primaryRS);
429 this.minDispersionNum = dispersionNum;
430 } else if (dispersionNum == this.minDispersionNum) {
431 this.minDispersionNumServerSet.add(primaryRS);
432 }
433
434 dispersionScoreSummary += dispersionScore;
435 dispersionNumSummary += dispersionNum;
436 }
437
438
439 if (primaryRSToRegionCounterMap.keySet().size() != 0) {
440 this.avgDispersionScore = dispersionScoreSummary /
441 (float) primaryRSToRegionCounterMap.keySet().size();
442 this.avgDispersionNum = dispersionNumSummary /
443 (float) primaryRSToRegionCounterMap.keySet().size();
444 }
445 }
446
447
448
449
450
451
452
453 public List<Float> getDispersionInformation() {
454 List<Float> dispersion = new ArrayList<Float>();
455 dispersion.add(avgDispersionScore);
456 dispersion.add(maxDispersionScore);
457 dispersion.add(minDispersionScore);
458 return dispersion;
459 }
460
461 public void print(boolean isDetailMode) {
462 if (!isFilledUp) {
463 System.err.println("[Error] Region assignment verfication report" +
464 "hasn't been filled up");
465 }
466 DecimalFormat df = new java.text.DecimalFormat( "#.##");
467
468
469 System.out.println("Region Assignment Verification for Table: " + tableName +
470 "\n\tTotal regions : " + totalRegions);
471
472
473 System.out.println("\tTotal regions on favored nodes " +
474 totalFavoredAssignments);
475 for (FavoredNodesPlan.Position p : FavoredNodesPlan.Position.values()) {
476 System.out.println("\t\tTotal regions on "+ p.toString() +
477 " region servers: " + favoredNodes[p.ordinal()]);
478 }
479
480 System.out.println("\tTotal unassigned regions: " +
481 unAssignedRegionsList.size());
482 if (isDetailMode) {
483 for (HRegionInfo region : unAssignedRegionsList) {
484 System.out.println("\t\t" + region.getRegionNameAsString());
485 }
486 }
487
488 System.out.println("\tTotal regions NOT on favored nodes: " +
489 nonFavoredAssignedRegionList.size());
490 if (isDetailMode) {
491 for (HRegionInfo region : nonFavoredAssignedRegionList) {
492 System.out.println("\t\t" + region.getRegionNameAsString());
493 }
494 }
495
496 System.out.println("\tTotal regions without favored nodes: " +
497 regionsWithoutValidFavoredNodes.size());
498 if (isDetailMode) {
499 for (HRegionInfo region : regionsWithoutValidFavoredNodes) {
500 System.out.println("\t\t" + region.getRegionNameAsString());
501 }
502 }
503
504
505 if (this.enforceLocality && totalRegions != 0) {
506
507 float actualLocality = 100 *
508 this.actualLocalitySummary / (float) totalRegions;
509 System.out.println("\n\tThe actual avg locality is " +
510 df.format(actualLocality) + " %");
511
512
513
514 for (FavoredNodesPlan.Position p : FavoredNodesPlan.Position.values()) {
515 float avgLocality = 100 *
516 (favoredNodesLocalitySummary[p.ordinal()] / (float) totalRegions);
517 System.out.println("\t\tThe expected avg locality if all regions" +
518 " on the " + p.toString() + " region servers: "
519 + df.format(avgLocality) + " %");
520 }
521 }
522
523
524 System.out.println("\n\tTotal hosting region servers: " +
525 totalRegionServers);
526
527 if (totalRegionServers != 0) {
528 System.out.println(
529 "\tAvg dispersion num: " +df.format(avgDispersionNum) +
530 " hosts;\tMax dispersion num: " + df.format(maxDispersionNum) +
531 " hosts;\tMin dispersion num: " + df.format(minDispersionNum) +
532 " hosts;");
533
534 System.out.println("\t\tThe number of the region servers with the max" +
535 " dispersion num: " + this.maxDispersionNumServerSet.size());
536 if (isDetailMode) {
537 printHServerAddressSet(maxDispersionNumServerSet);
538 }
539
540 System.out.println("\t\tThe number of the region servers with the min" +
541 " dispersion num: " + this.minDispersionNumServerSet.size());
542 if (isDetailMode) {
543 printHServerAddressSet(maxDispersionNumServerSet);
544 }
545
546 System.out.println(
547 "\tAvg dispersion score: " + df.format(avgDispersionScore) +
548 ";\tMax dispersion score: " + df.format(maxDispersionScore) +
549 ";\tMin dispersion score: " + df.format(minDispersionScore) + ";");
550
551 System.out.println("\t\tThe number of the region servers with the max" +
552 " dispersion score: " + this.maxDispersionScoreServerSet.size());
553 if (isDetailMode) {
554 printHServerAddressSet(maxDispersionScoreServerSet);
555 }
556
557 System.out.println("\t\tThe number of the region servers with the min" +
558 " dispersion score: " + this.minDispersionScoreServerSet.size());
559 if (isDetailMode) {
560 printHServerAddressSet(minDispersionScoreServerSet);
561 }
562
563 System.out.println(
564 "\tAvg regions/region server: " + df.format(avgRegionsOnRS) +
565 ";\tMax regions/region server: " + maxRegionsOnRS +
566 ";\tMin regions/region server: " + minRegionsOnRS + ";");
567
568
569 System.out.println("\t\tThe number of the most loaded region servers: "
570 + mostLoadedRSSet.size());
571 if (isDetailMode) {
572 printHServerAddressSet(mostLoadedRSSet);
573 }
574
575
576 System.out.println("\t\tThe number of the least loaded region servers: "
577 + leastLoadedRSSet.size());
578 if (isDetailMode) {
579 printHServerAddressSet(leastLoadedRSSet);
580 }
581 }
582 System.out.println("==============================");
583 }
584
585
586
587
588
589 List<HRegionInfo> getUnassignedRegions() {
590 return unAssignedRegionsList;
591 }
592
593
594
595
596
597 List<HRegionInfo> getRegionsWithoutValidFavoredNodes() {
598 return regionsWithoutValidFavoredNodes;
599 }
600
601
602
603
604
605 List<HRegionInfo> getNonFavoredAssignedRegions() {
606 return nonFavoredAssignedRegionList;
607 }
608
609
610
611
612
613 int getTotalFavoredAssignments() {
614 return totalFavoredAssignments;
615 }
616
617
618
619
620
621
622
623 int getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position position) {
624 return favoredNodes[position.ordinal()];
625 }
626
627 private void printHServerAddressSet(Set<ServerName> serverSet) {
628 if (serverSet == null) {
629 return ;
630 }
631 int i = 0;
632 for (ServerName addr : serverSet){
633 if ((i++) % 3 == 0) {
634 System.out.print("\n\t\t\t");
635 }
636 System.out.print(addr.getHostAndPort() + " ; ");
637 }
638 System.out.println("\n");
639 }
640 }