Index: src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java (revision 1188986) +++ src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java (working copy) @@ -24,8 +24,8 @@ import java.io.IOException; import java.lang.Thread.UncaughtExceptionHandler; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -57,19 +57,19 @@ import org.apache.hadoop.hbase.catalog.MetaReader; import org.apache.hadoop.hbase.catalog.RootLocationEditor; import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.executor.EventHandler.EventType; import org.apache.hadoop.hbase.executor.ExecutorService; import org.apache.hadoop.hbase.executor.RegionTransitionData; -import org.apache.hadoop.hbase.executor.EventHandler.EventType; -import org.apache.hadoop.hbase.regionserver.RegionAlreadyInTransitionException; -import org.apache.hadoop.hbase.regionserver.RegionOpeningState; import org.apache.hadoop.hbase.ipc.ServerNotRunningYetException; -import org.apache.hadoop.hbase.master.RegionPlan; +import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; import org.apache.hadoop.hbase.master.handler.ClosedRegionHandler; import org.apache.hadoop.hbase.master.handler.DisableTableHandler; import org.apache.hadoop.hbase.master.handler.EnableTableHandler; import org.apache.hadoop.hbase.master.handler.OpenedRegionHandler; import org.apache.hadoop.hbase.master.handler.ServerShutdownHandler; import org.apache.hadoop.hbase.master.handler.SplitRegionHandler; +import org.apache.hadoop.hbase.regionserver.RegionAlreadyInTransitionException; +import org.apache.hadoop.hbase.regionserver.RegionOpeningState; import org.apache.hadoop.hbase.regionserver.RegionServerStoppedException; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; @@ -706,7 +706,7 @@ // what follows will fail because not in expected state. regionState.update(RegionState.State.CLOSED, data.getStamp(), data.getOrigin()); - removeClosedRegion(regionState.getRegion()); + removeClosedRegion(regionState.getRegion()); this.executorService.submit(new ClosedRegionHandler(master, this, regionState.getRegion())); break; @@ -1835,6 +1835,20 @@ } /** + * Assigns all user regions to online servers. Use round-robin assignment. + * + * @param regions + * @throws IOException + * @throws InterruptedException + */ + public void assignUserRegionsToOnlineServers(List regions) + throws IOException, + InterruptedException { + List servers = this.serverManager.getOnlineServersList(); + assignUserRegions(regions, servers); + } + + /** * Assigns all user regions, if any. Used during cluster startup. *

* This is a synchronous call and will return once every region has been @@ -1919,7 +1933,8 @@ } @Override - public boolean bulkAssign(boolean sync) throws InterruptedException { + public boolean bulkAssign(boolean sync) throws InterruptedException, + IOException { // Disable timing out regions in transition up in zk while bulk assigning. this.assignmentManager.timeoutMonitor.bulkAssign(true); try { Index: src/main/java/org/apache/hadoop/hbase/master/BulkAssigner.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/BulkAssigner.java (revision 1188986) +++ src/main/java/org/apache/hadoop/hbase/master/BulkAssigner.java (working copy) @@ -19,6 +19,7 @@ */ package org.apache.hadoop.hbase.master; +import java.io.IOException; import java.lang.Thread.UncaughtExceptionHandler; import java.util.concurrent.Executors; @@ -35,7 +36,7 @@ * Server. */ public abstract class BulkAssigner { - final Server server; + protected final Server server; /** * @param server An instance of Server @@ -71,19 +72,24 @@ getLong("hbase.bulk.assignment.waiton.empty.rit", 5 * 60 * 1000); } - protected abstract void populatePool(final java.util.concurrent.ExecutorService pool); + protected abstract void populatePool( + final java.util.concurrent.ExecutorService pool) throws IOException; - public boolean bulkAssign() throws InterruptedException { + public boolean bulkAssign() throws InterruptedException, IOException { return bulkAssign(true); } /** * Run the bulk assign. - * @param sync Whether to assign synchronously. + * + * @param sync + * Whether to assign synchronously. * @throws InterruptedException * @return True if done. + * @throws IOException */ - public boolean bulkAssign(boolean sync) throws InterruptedException { + public boolean bulkAssign(boolean sync) throws InterruptedException, + IOException { boolean result = false; ThreadFactoryBuilder builder = new ThreadFactoryBuilder(); builder.setDaemon(true); Index: src/main/java/org/apache/hadoop/hbase/master/BulkReOpen.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/BulkReOpen.java (revision 1188986) +++ src/main/java/org/apache/hadoop/hbase/master/BulkReOpen.java (working copy) @@ -19,18 +19,16 @@ */ package org.apache.hadoop.hbase.master; +import java.io.IOException; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; +import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.Server; import org.apache.hadoop.hbase.ServerName; -import org.apache.hadoop.hbase.master.AssignmentManager; -import org.apache.hadoop.hbase.master.BulkAssigner; -import org.apache.hadoop.hbase.master.RegionPlan; -import org.apache.commons.logging.Log; /** * Performs bulk reopen of the list of regions provided to it. @@ -93,7 +91,7 @@ "hbase.bulk.reopen.threadpool.size", defaultThreadCount); } - public boolean bulkReOpen() throws InterruptedException { + public boolean bulkReOpen() throws InterruptedException, IOException { return bulkAssign(); } } Index: src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java (revision 1188986) +++ src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java (working copy) @@ -169,15 +169,29 @@ } @Override - protected void populatePool(ExecutorService pool) { - for (HRegionInfo region: regions) { - if (assignmentManager.isRegionInTransition(region) != null) continue; - final HRegionInfo hri = region; - pool.execute(new Runnable() { - public void run() { - assignmentManager.assign(hri, true); + protected void populatePool(ExecutorService pool) throws IOException { + boolean roundRobinAssignment = this.server.getConfiguration().getBoolean( + "hbase.master.enabletable.roundrobin", false); + + if (!roundRobinAssignment) { + for (HRegionInfo region : regions) { + if (assignmentManager.isRegionInTransition(region) != null) { + continue; } - }); + final HRegionInfo hri = region; + pool.execute(new Runnable() { + public void run() { + assignmentManager.assign(hri, true); + } + }); + } + } else { + try { + assignmentManager.assignUserRegionsToOnlineServers(regions); + } catch (InterruptedException e) { + LOG.warn("Assignment was interrupted"); + Thread.currentThread().interrupt(); + } } } Index: src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java (revision 1188986) +++ src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java (working copy) @@ -27,6 +27,8 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -42,10 +44,8 @@ import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HServerAddress; -import org.apache.hadoop.hbase.HServerInfo; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.NotServingRegionException; -import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.TableExistsException; import org.apache.hadoop.hbase.TableNotDisabledException; import org.apache.hadoop.hbase.TableNotEnabledException; @@ -53,16 +53,11 @@ import org.apache.hadoop.hbase.executor.EventHandler; import org.apache.hadoop.hbase.executor.EventHandler.EventType; import org.apache.hadoop.hbase.executor.ExecutorService; -import org.apache.hadoop.hbase.ipc.HRegionInterface; import org.apache.hadoop.hbase.master.MasterServices; import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hbase.regionserver.HRegionServer; -import org.apache.hadoop.hbase.regionserver.wal.HLog; import org.apache.hadoop.hbase.regionserver.wal.TestHLogUtils; import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.zookeeper.ZKAssign; -import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; -import org.apache.zookeeper.KeeperException; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -84,6 +79,8 @@ TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100); TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250); TEST_UTIL.getConfiguration().setInt("hbase.client.retries.number", 6); + TEST_UTIL.getConfiguration().setBoolean( + "hbase.master.enabletable.roundrobin", true); TEST_UTIL.startMiniCluster(3); } @@ -579,6 +576,60 @@ } /** + * Test round-robin assignment on enableTable. + * + * @throws IOException + */ + @Test + public void testEnableTableRoundRobinAssignment() throws IOException { + byte[] tableName = Bytes.toBytes("testEnableTableAssignment"); + byte[][] splitKeys = { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 }, + new byte[] { 3, 3, 3 }, new byte[] { 4, 4, 4 }, new byte[] { 5, 5, 5 }, + new byte[] { 6, 6, 6 }, new byte[] { 7, 7, 7 }, new byte[] { 8, 8, 8 }, + new byte[] { 9, 9, 9 } }; + int expectedRegions = splitKeys.length + 1; + HTableDescriptor desc = new HTableDescriptor(tableName); + desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY)); + admin.createTable(desc, splitKeys); + HTable ht = new HTable(TEST_UTIL.getConfiguration(), tableName); + Map regions = ht.getRegionsInfo(); + assertEquals("Tried to create " + expectedRegions + " regions " + + "but only found " + regions.size(), expectedRegions, regions.size()); + // Disable table. + admin.disableTable(tableName); + // Enable table, use round-robin assignment to assign regions. + admin.enableTable(tableName); + + // Check the assignment. + HTable metaTable = new HTable(HConstants.META_TABLE_NAME); + List regionInfos = admin.getTableRegions(tableName); + Map serverMap = new HashMap(); + for (int i = 0, j = regionInfos.size(); i < j; i++) { + HRegionInfo hri = regionInfos.get(i); + Get get = new Get(hri.getRegionName()); + Result result = metaTable.get(get); + String server = Bytes.toString(result.getValue(HConstants.CATALOG_FAMILY, + HConstants.SERVER_QUALIFIER)); + Integer regioncount = serverMap.get(server); + if (regioncount == null) { + regioncount = 0; + } + regioncount++; + serverMap.put(server, regioncount); + } + List> entryList = new ArrayList>( + serverMap.entrySet()); + Collections.sort(entryList, new Comparator>() { + public int compare(Map.Entry oa, + Map.Entry ob) { + return (oa.getValue() - ob.getValue()); + } + }); + assertTrue(entryList.size() == 3); + assertTrue((entryList.get(2).getValue() - entryList.get(0).getValue()) < 2); + } + + /** * Multi-family scenario. Tests forcing split from client and * having scanners successfully ride over split. * @throws Exception