View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
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   * Helper class that is used by {@link RegionPlacementMaintainer} to print
39   * information for favored nodes
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    // for unassigned regions
54    private List<HRegionInfo> unAssignedRegionsList =
55      new ArrayList<HRegionInfo>();
56  
57    // For regions without valid favored nodes
58    private List<HRegionInfo> regionsWithoutValidFavoredNodes =
59      new ArrayList<HRegionInfo>();
60  
61    // For regions not running on the favored nodes
62    private List<HRegionInfo> nonFavoredAssignedRegionList =
63      new ArrayList<HRegionInfo>();
64  
65    // For regions running on the favored nodes
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    // For region balancing information
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      // Set the table name
100     this.tableName = tableName;
101 
102     // Get all the regions for this table
103     List<HRegionInfo> regionInfoList =
104       snapshot.getTableToRegionMap().get(tableName);
105     // Get the total region num for the current table
106     this.totalRegions = regionInfoList.size();
107 
108     // Get the existing assignment plan
109     FavoredNodesPlan favoredNodesAssignment = snapshot.getExistingAssignmentPlan();
110     // Get the region to region server mapping
111     Map<HRegionInfo, ServerName> currentAssignment =
112       snapshot.getRegionToRegionServerMap();
113     // Initialize the server to its hosing region counter map
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     // Check the favored nodes and its locality information
123     // Also keep tracker of the most loaded and least loaded region servers
124     for (HRegionInfo region : regionInfoList) {
125       try {
126         ServerName currentRS = currentAssignment.get(region);
127         // Handle unassigned regions
128         if (currentRS == null) {
129           unAssignedRegionsList.add(region);
130           continue;
131         }
132 
133         // Keep updating the server to is hosting region counter map
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         // Get the favored nodes from the assignment plan and verify it.
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         // Get the primary, secondary and tertiary region server
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         // Update the primary rs to its region set map
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         // Update the primary rs to secondary and tertiary rs map
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         // Get the position of the current region server in the favored nodes list
174         FavoredNodesPlan.Position favoredNodePosition =
175           FavoredNodesPlan.getFavoredServerPosition(favoredNodes, currentRS);
176 
177         // Handle the non favored assignment.
178         if (favoredNodePosition == null) {
179           nonFavoredAssignedRegionList.add(region);
180           continue;
181         }
182         // Increase the favored nodes assignment.
183         this.favoredNodes[favoredNodePosition.ordinal()]++;
184         totalFavoredAssignments++;
185 
186         // Summary the locality information for each favored nodes
187         if (regionLocalityMap != null) {
188           // Set the enforce locality as true;
189           this.enforceLocality = true;
190 
191           // Get the region degree locality map
192           Map<String, Float> regionDegreeLocalityMap =
193             regionLocalityMap.get(region.getEncodedName());
194           if (regionDegreeLocalityMap == null) {
195             continue; // ignore the region which doesn't have any store files.
196           }
197 
198           // Get the locality summary for each favored nodes
199           for (FavoredNodesPlan.Position p : FavoredNodesPlan.Position.values()) {
200             ServerName favoredNode = favoredNodes.get(p.ordinal());
201             // Get the locality for the current favored nodes
202             Float locality =
203               regionDegreeLocalityMap.get(favoredNode.getHostname());
204             if (locality != null) {
205               this.favoredNodesLocalitySummary[p.ordinal()] += locality;
206             }
207           }
208 
209           // Get the locality summary for the current region server
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     // Calculate the secondary score for each primary region server
226     for (Map.Entry<ServerName, Integer> entry :
227       primaryRSToRegionCounterMap.entrySet()) {
228       ServerName primaryRS = entry.getKey();
229       Integer regionsOnPrimary = entry.getValue();
230 
231       // Process the dispersion number and score
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       // Update the max dispersion score
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       // Update the max dispersion num
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       // Update the min dispersion score
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       // Update the min dispersion num
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     // Update the avg dispersion score
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     // Fill up the most loaded and least loaded region server information
289     for (Map.Entry<ServerName, Integer> entry :
290       serverToHostingRegionCounterMap.entrySet()) {
291       ServerName currentRS = entry.getKey();
292       int hostRegionCounter = entry.getValue().intValue();
293 
294       // Update the most loaded region server list and maxRegionsOnRS
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       // Update the least loaded region server list and minRegionsOnRS
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     // and total region servers
314     this.totalRegionServers = serverToHostingRegionCounterMap.keySet().size();
315     this.avgRegionsOnRS = (totalRegionServers == 0) ? 0 :
316       (totalRegions / (float) totalRegionServers);
317     // Set the isFilledUp as true
318     isFilledUp = true;
319   }
320 
321   /**
322    * Use this to project the dispersion scores
323    * @param tableName
324    * @param snapshot
325    * @param newPlan
326    */
327   public void fillUpDispersion(TableName tableName,
328       SnapshotOfRegionAssignmentFromMeta snapshot, FavoredNodesPlan newPlan) {
329     // Set the table name
330     this.tableName = tableName;
331     // Get all the regions for this table
332     List<HRegionInfo> regionInfoList = snapshot.getTableToRegionMap().get(
333         tableName);
334     // Get the total region num for the current table
335     this.totalRegions = regionInfoList.size();
336     FavoredNodesPlan plan = null;
337     if (newPlan == null) {
338       plan = snapshot.getExistingAssignmentPlan();
339     } else {
340       plan = newPlan;
341     }
342     // Get the region to region server mapping
343     Map<ServerName, Integer> primaryRSToRegionCounterMap =
344         new HashMap<ServerName, Integer>();
345     Map<ServerName, Set<ServerName>> primaryToSecTerRSMap =
346         new HashMap<ServerName, Set<ServerName>>();
347 
348     // Check the favored nodes and its locality information
349     // Also keep tracker of the most loaded and least loaded region servers
350     for (HRegionInfo region : regionInfoList) {
351       try {
352         // Get the favored nodes from the assignment plan and verify it.
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         // Get the primary, secondary and tertiary region server
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         // Update the primary rs to its region set map
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         // Update the primary rs to secondary and tertiary rs map
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     // Calculate the secondary score for each primary region server
392     for (Map.Entry<ServerName, Integer> entry :
393       primaryRSToRegionCounterMap.entrySet()) {
394       ServerName primaryRS = entry.getKey();
395       Integer regionsOnPrimary = entry.getValue();
396 
397       // Process the dispersion number and score
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       // Update the max dispersion num
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       // Update the min dispersion score
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       // Update the min dispersion num
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     // Update the avg dispersion score
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    * @return list which contains just 3 elements: average dispersion score, max
449    * dispersion score and min dispersion score as first, second and third element
450    * respectively.
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     // Print some basic information
469     System.out.println("Region Assignment Verification for Table: " + tableName +
470         "\n\tTotal regions : " + totalRegions);
471 
472     // Print the number of regions on each kinds of the favored nodes
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     // Print the number of regions in each kinds of invalid assignment
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     // Print the locality information if enabled
505     if (this.enforceLocality && totalRegions != 0) {
506       // Print the actual locality for this table
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       // Print the expected locality if regions are placed on the each kinds of
513       // favored nodes
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     // Print the region balancing information
524     System.out.println("\n\tTotal hosting region servers: " +
525         totalRegionServers);
526     // Print the region balance information
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       // Print the details about the most loaded region servers
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       // Print the details about the least loaded region servers
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    * Return the unassigned regions
587    * @return unassigned regions
588    */
589   List<HRegionInfo> getUnassignedRegions() {
590     return unAssignedRegionsList;
591   }
592 
593   /**
594    * Return the regions without favored nodes
595    * @return regions without favored nodes
596    */
597   List<HRegionInfo> getRegionsWithoutValidFavoredNodes() {
598     return regionsWithoutValidFavoredNodes;
599   }
600 
601   /**
602    * Return the regions not assigned to its favored nodes
603    * @return regions not assigned to its favored nodes
604    */
605   List<HRegionInfo> getNonFavoredAssignedRegions() {
606     return nonFavoredAssignedRegionList;
607   }
608   
609   /**
610    * Return the number of regions assigned to their favored nodes
611    * @return number of regions assigned to their favored nodes
612    */
613   int getTotalFavoredAssignments() {
614     return totalFavoredAssignments;
615   }
616 
617   /**
618    * Return the number of regions based on the position (primary/secondary/
619    * tertiary) assigned to their favored nodes
620    * @param position
621    * @return the number of regions
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 }