Index: src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java (revision 1226649) +++ src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java (working copy) @@ -169,9 +169,16 @@ LOG.debug(server.getServerName() + " Avg: " + avg + " actual: " + serverLoad); if (!(avg > 2.0 && serverLoad <= avgLoadPlusSlop && serverLoad >= avgLoadMinusSlop)) { - LOG.debug(server.getServerName() + " Isn't balanced!!! Avg: " + avg + - " actual: " + serverLoad + " slop: " + slop); - success = false; + for (HRegionInfo hri : server.getOnlineRegions()) { + if (hri.isMetaRegion() || hri.isRootRegion()) serverLoad--; + // LOG.debug(hri.getRegionNameAsString()); + } + if (!(serverLoad <= avgLoadPlusSlop && serverLoad >= avgLoadMinusSlop)) { + LOG.debug(server.getServerName() + " Isn't balanced!!! Avg: " + avg + + " actual: " + serverLoad + " slop: " + slop); + success = false; + break; + } } } Index: src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java (revision 1226649) +++ src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java (working copy) @@ -49,6 +49,7 @@ import org.apache.hadoop.hbase.Chore; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HServerLoad; import org.apache.hadoop.hbase.NotServingRegionException; import org.apache.hadoop.hbase.Server; import org.apache.hadoop.hbase.ServerName; @@ -2782,6 +2783,55 @@ } /** + * This is an EXPENSIVE clone. Cloning though is the safest thing to do. + * Can't let out original since it can change and at least the loadbalancer + * wants to iterate this exported list. We need to synchronize on regions + * since all access to this.servers is under a lock on this.regions. + * + * @return A clone of current assignments by table. + */ + Map>> getAssignmentsByTable() { + Map>> result = null; + synchronized (this.regions) { + result = new HashMap>>(); + if (!this.master.getConfiguration(). + getBoolean("hbase.master.loadbalance.bytable", true)) { + result.put("ensemble", getAssignments()); + } else { + for (Map.Entry> e: this.servers.entrySet()) { + for (HRegionInfo hri : e.getValue()) { + if (hri.isMetaRegion() || hri.isRootRegion()) continue; + String tablename = hri.getTableNameAsString(); + Map> svrToRegions = result.get(tablename); + if (svrToRegions == null) { + svrToRegions = new HashMap>(this.servers.size()); + result.put(tablename, svrToRegions); + } + List regions = null; + if (!svrToRegions.containsKey(e.getKey())) { + regions = new ArrayList(); + svrToRegions.put(e.getKey(), regions); + } else { + regions = svrToRegions.get(e.getKey()); + } + regions.add(hri); + } + } + } + } + Map onlineSvrs = this.serverManager.getOnlineServers(); + // Take care of servers w/o assignments. + for (Map> map : result.values()) { + for (Map.Entry svrEntry: onlineSvrs.entrySet()) { + if (!map.containsKey(svrEntry.getKey())) { + map.put(svrEntry.getKey(), new ArrayList()); + } + } + } + return result; + } + + /** * @return A clone of current assignments. Note, this is assignments only. * If a new server has come in and it has no regions, it will not be included * in the returned Map. Index: src/main/java/org/apache/hadoop/hbase/master/HMaster.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/HMaster.java (revision 1226649) +++ src/main/java/org/apache/hadoop/hbase/master/HMaster.java (working copy) @@ -945,16 +945,14 @@ } } - Map> assignments = - this.assignmentManager.getAssignments(); - // Returned Map from AM does not include mention of servers w/o assignments. - for (Map.Entry e: - this.serverManager.getOnlineServers().entrySet()) { - if (!assignments.containsKey(e.getKey())) { - assignments.put(e.getKey(), new ArrayList()); - } + Map>> assignmentsByTable = + this.assignmentManager.getAssignmentsByTable(); + + List plans = new ArrayList(); + for (Map> assignments : assignmentsByTable.values()) { + List partialPlans = this.balancer.balanceCluster(assignments); + if (partialPlans != null) plans.addAll(partialPlans); } - List plans = this.balancer.balanceCluster(assignments); int rpCount = 0; // number of RegionPlans balanced so far long totalRegPlanExecTime = 0; balancerRan = plans != null;