Index: src/main/java/org/apache/hadoop/hbase/HConstants.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/HConstants.java (revision 1042242) +++ src/main/java/org/apache/hadoop/hbase/HConstants.java (working copy) @@ -299,6 +299,14 @@ } /** + * flags that are passed to createTable() + */ + public enum TableCreationFlag { + SYNC, // indicates waiting for assignment of regions before call to createTable() returns + ROUND_ROBIN // assigns the regions in round-robin fashion across all region servers + } + + /** * Scope tag for locally scoped data. * This data will not be replicated. */ Index: src/main/java/org/apache/hadoop/hbase/master/HMaster.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/HMaster.java (revision 1042242) +++ src/main/java/org/apache/hadoop/hbase/master/HMaster.java (working copy) @@ -25,6 +25,8 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @@ -48,6 +50,7 @@ import org.apache.hadoop.hbase.TableNotDisabledException; import org.apache.hadoop.hbase.TableNotFoundException; import org.apache.hadoop.hbase.UnknownRegionException; +import org.apache.hadoop.hbase.HConstants.TableCreationFlag; import org.apache.hadoop.hbase.catalog.CatalogTracker; import org.apache.hadoop.hbase.catalog.MetaEditor; import org.apache.hadoop.hbase.catalog.MetaReader; @@ -64,6 +67,7 @@ import org.apache.hadoop.hbase.ipc.HMasterInterface; import org.apache.hadoop.hbase.ipc.HMasterRegionInterface; import org.apache.hadoop.hbase.ipc.RpcServer; +import org.apache.hadoop.hbase.master.AssignmentManager.BulkStartupAssigner; import org.apache.hadoop.hbase.master.LoadBalancer.RegionPlan; import org.apache.hadoop.hbase.master.handler.DeleteTableHandler; import org.apache.hadoop.hbase.master.handler.DisableTableHandler; @@ -721,14 +725,14 @@ this.assignmentManager.balance(rp); } } - + public void createTable(HTableDescriptor desc, byte [][] splitKeys) throws IOException { - createTable(desc, splitKeys, false); + createTable(desc, splitKeys, new TableCreationFlag[0]); } public void createTable(HTableDescriptor desc, byte [][] splitKeys, - boolean sync) + TableCreationFlag[] flags) throws IOException { if (!isMasterRunning()) { throw new MasterNotRunningException(); @@ -757,11 +761,21 @@ LOG.warn("Interrupted waiting for meta availability", e); throw new IOException(e); } - createTable(newRegions, sync); + createTable(newRegions, flags); } + protected boolean arrayContains(T[] array, T ele) { + if (array == null || array.length == 0) + return false; + for (int i = 0; i < array.length; i++) { + if (ele == array[i]) + return true; + } + return false; + } + private synchronized void createTable(final HRegionInfo [] newRegions, - boolean sync) + TableCreationFlag[] flags) throws IOException { String tableName = newRegions[0].getTableDesc().getNameAsString(); if(MetaReader.tableExists(catalogTracker, tableName)) { @@ -789,11 +803,31 @@ region.getLog().closeAndDelete(); // 5. Trigger immediate assignment of this region - assignmentManager.assign(region.getRegionInfo(), true); + if (!arrayContains(flags, TableCreationFlag.ROUND_ROBIN)) { + assignmentManager.assign(region.getRegionInfo(), true); + } } - + + if (arrayContains(flags, TableCreationFlag.ROUND_ROBIN)) { + Map> bulkPlan = null; + List servers = serverManager.getOnlineServersList(); + // Generate a round-robin bulk assignment plan + bulkPlan = LoadBalancer.roundRobinAssignment( + Arrays.asList(newRegions), servers); + LOG.info("Bulk assigning " + newRegions.length + " region(s) across " + + servers.size() + " server(s)"); + // Use fixed count thread pool assigning. + BulkAssigner ba = new BulkStartupAssigner(this, bulkPlan, this.assignmentManager); + try { + ba.bulkAssign(); + } catch (InterruptedException ie) { + LOG.warn("Caught " + ie + " during round-robin assignment"); + } + LOG.info("Bulk assigning done"); + } + // 5. If sync, wait for assignment of regions - if(sync) { + if (arrayContains(flags, TableCreationFlag.SYNC)) { LOG.debug("Waiting for " + newRegions.length + " region(s) to be " + "assigned before returning"); for(HRegionInfo regionInfo : newRegions) { Index: src/main/java/org/apache/hadoop/hbase/io/HbaseObjectWritable.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/io/HbaseObjectWritable.java (revision 1042242) +++ src/main/java/org/apache/hadoop/hbase/io/HbaseObjectWritable.java (working copy) @@ -23,6 +23,7 @@ import java.io.IOException; import java.lang.reflect.Array; import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -42,6 +43,7 @@ import org.apache.hadoop.hbase.HServerInfo; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.HConstants.TableCreationFlag; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.Increment; @@ -192,6 +194,7 @@ addToMap(List.class, code++); + addToMap(TableCreationFlag[].class, code++); addToMap(NavigableSet.class, code++); addToMap(ColumnPrefixFilter.class, code++); Index: src/main/java/org/apache/hadoop/hbase/ipc/HMasterInterface.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/ipc/HMasterInterface.java (revision 1042242) +++ src/main/java/org/apache/hadoop/hbase/ipc/HMasterInterface.java (working copy) @@ -20,11 +20,13 @@ package org.apache.hadoop.hbase.ipc; import java.io.IOException; +import java.util.EnumSet; import org.apache.hadoop.hbase.ClusterStatus; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.UnknownRegionException; +import org.apache.hadoop.hbase.HConstants.TableCreationFlag; /** * Clients interact with the HMasterInterface to gain access to meta-level @@ -48,9 +50,10 @@ * the table will be created with a single region. * @param desc table descriptor * @param splitKeys + * @param flags table creation flags: sync, round-robin * @throws IOException */ - public void createTable(HTableDescriptor desc, byte [][] splitKeys) + public void createTable(HTableDescriptor desc, byte [][] splitKeys, TableCreationFlag[] flags) throws IOException; /** Index: src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java (revision 1042242) +++ src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java (working copy) @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.Arrays; +import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.NavigableMap; @@ -43,10 +44,12 @@ import org.apache.hadoop.hbase.TableExistsException; import org.apache.hadoop.hbase.UnknownRegionException; import org.apache.hadoop.hbase.ZooKeeperConnectionException; +import org.apache.hadoop.hbase.HConstants.TableCreationFlag; import org.apache.hadoop.hbase.catalog.CatalogTracker; import org.apache.hadoop.hbase.catalog.MetaReader; import org.apache.hadoop.hbase.ipc.HMasterInterface; import org.apache.hadoop.hbase.ipc.HRegionInterface; +import org.apache.hadoop.hbase.master.HMaster; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.util.Writables; @@ -224,7 +227,7 @@ */ public void createTable(HTableDescriptor desc) throws IOException { - createTable(desc, null); + createTable(desc, null, new TableCreationFlag[0]); } /** @@ -264,7 +267,9 @@ if(splitKeys == null || splitKeys.length != numRegions - 1) { throw new IllegalArgumentException("Unable to split key range into enough regions"); } - createTable(desc, splitKeys); + TableCreationFlag[] flags = new TableCreationFlag[1]; + flags[0] = TableCreationFlag.ROUND_ROBIN; + createTable(desc, splitKeys, flags); } /** @@ -284,7 +289,7 @@ * and attempt-at-creation). * @throws IOException */ - public void createTable(HTableDescriptor desc, byte [][] splitKeys) + public void createTable(HTableDescriptor desc, byte [][] splitKeys, TableCreationFlag[] flags) throws IOException { HTableDescriptor.isLegalTableName(desc.getName()); if(splitKeys != null && splitKeys.length > 1) { @@ -300,7 +305,7 @@ lastKey = splitKey; } } - createTableAsync(desc, splitKeys); + createTableAsync(desc, splitKeys, flags); for (int tries = 0; tries < numRetries; tries++) { try { // Wait for new table to come on-line @@ -334,11 +339,11 @@ * and attempt-at-creation). * @throws IOException */ - public void createTableAsync(HTableDescriptor desc, byte [][] splitKeys) + public void createTableAsync(HTableDescriptor desc, byte [][] splitKeys, TableCreationFlag[] flags) throws IOException { HTableDescriptor.isLegalTableName(desc.getName()); try { - getMaster().createTable(desc, splitKeys); + getMaster().createTable(desc, splitKeys, flags); } catch (RemoteException e) { throw e.unwrapRemoteException(); }