You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by li...@apache.org on 2014/02/11 19:28:32 UTC

svn commit: r1567267 - in /hbase/branches/0.89-fb/src: main/java/org/apache/hadoop/hbase/client/ main/java/org/apache/hadoop/hbase/ipc/ main/java/org/apache/hadoop/hbase/master/ test/java/org/apache/hadoop/hbase/ test/java/org/apache/hadoop/hbase/client/

Author: liyin
Date: Tue Feb 11 18:28:31 2014
New Revision: 1567267

URL: http://svn.apache.org/r1567267
Log:
[0.89-fb][HBASE-10425] Hacky way to create a table on specified subset of machines

Author: adela

Summary: should not affect existing code

Test Plan: added unit test: TestHackyCreateTable; ran TestAdmin too - nothing is ruined

Reviewers: liyintang, manukranthk, aaiyer, gauravm

Reviewed By: liyintang

CC: hbase-eng@

Differential Revision: https://phabricator.fb.com/D1151470

Task ID: 3610285

Added:
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHackyCreateTable.java
Modified:
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/ipc/HMasterInterface.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/MiniHBaseCluster.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java?rev=1567267&r1=1567266&r2=1567267&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java Tue Feb 11 18:28:31 2014
@@ -265,18 +265,27 @@ public class HBaseAdmin {
   public void createTable(final HTableDescriptor desc, byte [][] splitKeys)
   throws IOException {
     HTableDescriptor.isLegalTableName(desc.getName());
-    if(splitKeys != null && splitKeys.length > 1) {
-      Arrays.sort(splitKeys, Bytes.BYTES_COMPARATOR);
-      // Verify there are no duplicate split keys
-      byte [] lastKey = null;
-      for(byte [] splitKey : splitKeys) {
-        if(lastKey != null && Bytes.equals(splitKey, lastKey)) {
-          throw new IllegalArgumentException("All split keys must be unique, found duplicate");
-        }
-        lastKey = splitKey;
-      }
-    }
+    checkSplitKeys(splitKeys);
     createTableAsync(desc, splitKeys);
+    checkTableOnline(desc, splitKeys);
+  }
+
+  /**
+   * Same like {@link #createTable(HTableDescriptor, byte[][])} but creates
+   * table on specific regionservers
+   *
+   * @throws IOException
+   */
+  public void createTable(final HTableDescriptor desc, byte[][] splitKeys,
+      List<HServerAddress> servers) throws IOException {
+    HTableDescriptor.isLegalTableName(desc.getName());
+    checkSplitKeys(splitKeys);
+    createTableAsyncAndPlaceOnServers(desc, splitKeys, servers);
+    checkTableOnline(desc, splitKeys);
+  }
+
+  private void checkTableOnline(final HTableDescriptor desc, byte[][] splitKeys)
+      throws IOException, RegionOfflineException, InterruptedIOException {
     int numRegs = splitKeys == null ? 1 : splitKeys.length + 1;
     int prevRegCount = 0;
     for (int tries = 0; tries < numRetries; ++tries) {
@@ -327,6 +336,21 @@ public class HBaseAdmin {
     }
   }
 
+  public void checkSplitKeys(byte[][] splitKeys) {
+    if (splitKeys != null && splitKeys.length > 1) {
+      Arrays.sort(splitKeys, Bytes.BYTES_COMPARATOR);
+      // Verify there are no duplicate split keys
+      byte[] lastKey = null;
+      for (byte[] splitKey : splitKeys) {
+        if (lastKey != null && Bytes.equals(splitKey, lastKey)) {
+          throw new IllegalArgumentException(
+              "All split keys must be unique, found duplicate");
+        }
+        lastKey = splitKey;
+      }
+    }
+  }
+
   /**
    * Creates a new table but does not block and wait for it to come online.
    * Asynchronous operation.
@@ -356,6 +380,31 @@ public class HBaseAdmin {
   }
 
   /**
+   * SAme as {@link #createTableAsync(HTableDescriptor, byte[][])} but using a
+   * specific set of servers to assign the regions
+   *
+   * @param desc
+   * @param splitKeys
+   * @param servers
+   * @throws IOException
+   */
+  public void createTableAsyncAndPlaceOnServers(HTableDescriptor desc,
+      byte[][] splitKeys, List<HServerAddress> servers) throws IOException {
+    if (this.master == null) {
+      throw new MasterNotRunningException("master has been shut down");
+    }
+    HTableDescriptor.isLegalTableName(desc.getName());
+    try {
+      this.master.createTableAndAssignOnServers(desc, splitKeys, servers);
+    } catch (RemoteException e) {
+      throw RemoteExceptionHandler.decodeRemoteException(e);
+    } catch (SocketTimeoutException ste) {
+      LOG.warn("Creating " + desc.getNameAsString() + " took too long", ste);
+    }
+  }
+
+
+  /**
    * Deletes a table.
    * Synchronous operation.
    *

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/ipc/HMasterInterface.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/ipc/HMasterInterface.java?rev=1567267&r1=1567266&r2=1567267&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/ipc/HMasterInterface.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/ipc/HMasterInterface.java Tue Feb 11 18:28:31 2014
@@ -26,6 +26,7 @@ import org.apache.hadoop.hbase.ClusterSt
 import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HServerAddress;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.util.Pair;
 import org.apache.hadoop.io.Writable;
@@ -58,6 +59,17 @@ public interface HMasterInterface extend
   throws IOException;
 
   /**
+   * Same like {@link #createTable(HTableDescriptor, byte[][])} above, but we
+   * specify the set of machines where we want the regions to be assigned
+   *
+   * @param desc
+   * @param splitKeys
+   * @throws IOException
+   */
+  public void createTableAndAssignOnServers(HTableDescriptor desc,
+      byte[][] splitKeys, List<HServerAddress> servers) throws IOException;
+
+  /**
    * Deletes a table
    * @param tableName table to delete
    * @throws IOException e

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/HMaster.java?rev=1567267&r1=1567266&r2=1567267&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/HMaster.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/HMaster.java Tue Feb 11 18:28:31 2014
@@ -1413,26 +1413,41 @@ public class HMaster extends HasThread i
     }
   }
 
-  @Override
-  public void createTable(HTableDescriptor desc, byte [][] splitKeys)
-  throws IOException {
+  /**
+   * Creates regionInfo for the new regions that are going to be part of the new
+   * table
+   *
+   * @param desc - descriptor of the new table
+   * @param splitKeys - split keys marking the start and end key for every region
+   * @return array of new HRegionInfo
+   * @throws IOException
+   */
+  public HRegionInfo[] createRegionsForNewTable(HTableDescriptor desc,
+      byte[][] splitKeys) throws IOException {
     if (!isMasterRunning()) {
       throw new MasterNotRunningException();
     }
-    HRegionInfo [] newRegions = null;
-    if(splitKeys == null || splitKeys.length == 0) {
-      newRegions = new HRegionInfo [] { new HRegionInfo(desc, null, null) };
+    HRegionInfo[] newRegions = null;
+    if (splitKeys == null || splitKeys.length == 0) {
+      newRegions = new HRegionInfo[] { new HRegionInfo(desc, null, null) };
     } else {
       int numRegions = splitKeys.length + 1;
       newRegions = new HRegionInfo[numRegions];
-      byte [] startKey = null;
-      byte [] endKey = null;
-      for(int i=0;i<numRegions;i++) {
+      byte[] startKey = null;
+      byte[] endKey = null;
+      for (int i = 0; i < numRegions; i++) {
         endKey = (i == splitKeys.length) ? null : splitKeys[i];
         newRegions[i] = new HRegionInfo(desc, startKey, endKey);
         startKey = endKey;
       }
     }
+    return newRegions;
+  }
+
+  @Override
+  public void createTable(HTableDescriptor desc, byte [][] splitKeys)
+  throws IOException {
+    HRegionInfo[] newRegions = createRegionsForNewTable(desc, splitKeys);
     try {
       // We can not create a table unless meta regions have already been
       // assigned and scanned.
@@ -1453,6 +1468,31 @@ public class HMaster extends HasThread i
     }
   }
 
+  @Override
+  public void createTableAndAssignOnServers(HTableDescriptor desc,
+      byte[][] splitKeys, List<HServerAddress> servers) throws IOException {
+    HRegionInfo[] newRegions = createRegionsForNewTable(desc, splitKeys);
+    try {
+      // We can not create a table unless meta regions have already been
+      // assigned and scanned.
+      if (!this.regionManager.areAllMetaRegionsOnline()) {
+        throw new NotAllMetaRegionsOnlineException();
+      }
+      if (!this.serverManager.hasEnoughRegionServers()) {
+        throw new IOException("not enough servers to create table yet");
+      }
+      createTable(newRegions, servers);
+      LOG.info("Succeeded in creating table " + desc.getNameAsString()
+          + "on the specified servers");
+    } catch (TableExistsException e) {
+      throw e;
+    } catch (IOException e) {
+      LOG.error("Cannot create table " + desc.getNameAsString()
+          + " because of " + e.toString() + " on the specified servers");
+      throw RemoteExceptionHandler.checkIOException(e);
+    }
+  }
+
   private static boolean tableExists(HRegionInterface srvr,
     byte[] metaRegionName, String tableName)
   throws IOException {
@@ -1477,8 +1517,39 @@ public class HMaster extends HasThread i
     return false;
   }
 
-  private synchronized void createTable(final HRegionInfo [] newRegions)
-  throws IOException {
+  private synchronized void createTable(final HRegionInfo[] newRegions)
+      throws IOException {
+    String tableName = newRegions[0].getTableDesc().getNameAsString();
+    AssignmentPlan assignmentPlan = null;
+    if (this.shouldAssignRegionsWithFavoredNodes) {
+      // Get the assignment domain for this table
+      AssignmentDomain domain = this.getAssignmentDomain(tableName);
+      // Get the assignment plan for the new regions
+      assignmentPlan = regionPlacement.getNewAssignmentPlan(newRegions, domain);
+    }
+    createTable(newRegions, assignmentPlan);
+  }
+
+  /**
+   * Create table such that we place the new regions on the specified machines
+   * @param newRegions - new regions from the new table
+   * @param servers - set of machines where we like the regions to be placed
+   * @throws IOException
+   */
+  private synchronized void createTable(final HRegionInfo[] newRegions,
+      List<HServerAddress> servers) throws IOException {
+    String tableName = newRegions[0].getTableDesc().getNameAsString();
+    AssignmentPlan assignmentPlan = null;
+    if (this.shouldAssignRegionsWithFavoredNodes) {
+      // Get the assignment domain for this table
+      AssignmentDomain domain = this.getAssignmentDomain(tableName, servers);
+      // Get the assignment plan for the new regions
+      assignmentPlan = regionPlacement.getNewAssignmentPlan(newRegions, domain);
+    }
+    createTable(newRegions, assignmentPlan);
+  }
+
+  private synchronized void createTable(final HRegionInfo[] newRegions, AssignmentPlan assignmentPlan) throws IOException {
     String tableName = newRegions[0].getTableDesc().getNameAsString();
     // 1. Check to see if table already exists. Get meta region where
     // table would sit should it exist. Open scanner on it. If a region
@@ -1499,15 +1570,6 @@ public class HMaster extends HasThread i
       if (tableExists(srvr, metaRegionName, tableName)) {
         throw new TableExistsException(tableName);
       }
-      AssignmentPlan assignmentPlan = null;
-      if (this.shouldAssignRegionsWithFavoredNodes) {
-        // Get the assignment domain for this table
-        AssignmentDomain domain = this.getAssignmentDomain(tableName);
-        // Get the assignment plan for the new regions
-        assignmentPlan =
-          regionPlacement.getNewAssignmentPlan(newRegions, domain);
-      }
-
       if (assignmentPlan == null) {
         LOG.info("Generated the assignment plan for new table " + tableName);
       } else {
@@ -1545,15 +1607,26 @@ public class HMaster extends HasThread i
     // Get all the online region servers
     List<HServerAddress> onlineRSList =
       this.serverManager.getOnlineRegionServerList();
-    
+    return getAssignmentDomain(tableName, onlineRSList);
+  }
+
+  /**
+   * Get the assignment domain for the table. Currently the domain would be
+   * generated by shuffling the passed region servers.
+   *
+   * It would be easy to extend for the multi-tenancy in the future.
+   *
+   * @param tableName
+   * @param servers - list of servers that we want to be included in the plan
+   * @return the assignment domain for the table.
+   */
+  private AssignmentDomain getAssignmentDomain(String tableName, List<HServerAddress> servers) {
     // Shuffle the server list based on the tableName
     Random random = new Random(tableName.hashCode());
-    Collections.shuffle(onlineRSList, random);
-    
+    Collections.shuffle(servers, random);
     // Add the shuffled server list into the assignment domain
     AssignmentDomain domain = new AssignmentDomain(this.conf);
-    domain.addServers(onlineRSList);
-    
+    domain.addServers(servers);
     return domain;
   }
   

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java?rev=1567267&r1=1567266&r2=1567267&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java Tue Feb 11 18:28:31 2014
@@ -122,7 +122,7 @@ public class RegionPlacement implements 
       // Place the secondary and tertiary region server
       Map<HRegionInfo, Pair<HServerAddress, HServerAddress>>
         secondaryAndTertiaryRSMap =
-        this.placeSecondaryAndTertiaryRS(primaryRSMap, domain);
+        this.placeSecondaryAndTertiaryWithRestrictions(primaryRSMap, domain);
 
       // Get the assignment plan by initialization with the primaryRSMap and the
       // secondaryAndTertiaryRSMap
@@ -283,6 +283,7 @@ public class RegionPlacement implements 
    * @return
    * @throws IOException
    */
+  @SuppressWarnings("unused")
   private Map<HRegionInfo, Pair<HServerAddress,HServerAddress>> placeSecondaryAndTertiaryRS(
       Map<HRegionInfo, HServerAddress> primaryRSMap, AssignmentDomain domain)
       throws IOException {

Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/MiniHBaseCluster.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/MiniHBaseCluster.java?rev=1567267&r1=1567266&r2=1567267&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/MiniHBaseCluster.java (original)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/MiniHBaseCluster.java Tue Feb 11 18:28:31 2014
@@ -30,7 +30,6 @@ import org.apache.commons.logging.LogFac
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.hbase.client.HConnectionManager;
-import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.master.HMaster;
 import org.apache.hadoop.hbase.regionserver.HRegion;
 import org.apache.hadoop.hbase.regionserver.HRegionServer;
@@ -489,6 +488,14 @@ public class MiniHBaseCluster {
     return index;
   }
 
+  public List<HServerAddress> getRegionServers() throws IOException {
+    List<HServerAddress> servers = new ArrayList<HServerAddress>();
+    for (JVMClusterUtil.RegionServerThread rst: getRegionServerThreads()) {
+      servers.add(rst.getRegionServer().getHServerInfo().getServerAddress());
+    }
+    return servers;
+  }
+
   /**
    * Add an exception to send when a region server checks back in
    * @param serverNumber Which server to send it to

Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java?rev=1567267&r1=1567266&r2=1567267&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java (original)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java Tue Feb 11 18:28:31 2014
@@ -60,6 +60,7 @@ public class TestAdmin {
   private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
   private HBaseAdmin admin;
   private static final int NUM_REGION_SERVER = 3;
+
   @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
@@ -653,9 +654,6 @@ public class TestAdmin {
     HTableDescriptor htd = this.admin.getTableDescriptor(tableName);
 
     HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
-    HTable table = new HTable(master.getConfiguration(),
-        tableName);
-    Map<HRegionInfo, HServerAddress> hriToHsa = table.getRegionsInfo();
 
     // Try adding a column
     this.admin.enableTable(tableName);

Added: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHackyCreateTable.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHackyCreateTable.java?rev=1567267&view=auto
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHackyCreateTable.java (added)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHackyCreateTable.java Tue Feb 11 18:28:31 2014
@@ -0,0 +1,143 @@
+/**
+ * Copyright The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.client;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HServerAddress;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Create table only on a set of regionservers instead of whole cluster
+ * JIRA: https://issues.apache.org/jira/browse/HBASE-10425
+ *
+ */
+public class TestHackyCreateTable {
+  final Log LOG = LogFactory.getLog(getClass());
+  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+  private HBaseAdmin admin;
+  private static final int NUM_REGION_SERVER = 10;
+  /**
+   * Number of regionservers that we will remove in the test from {@link #NUM_REGION_SERVER}
+   */
+  private static final int NUM_REMOVED_RS = 7;
+  @BeforeClass
+  public static void setUpBeforeClass() throws Exception {
+    TEST_UTIL.getConfiguration().set(HConstants.LOAD_BALANCER_IMPL,
+        "org.apache.hadoop.hbase.master.RegionManager$AssignmentLoadBalancer");
+    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.startMiniCluster(NUM_REGION_SERVER);
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TEST_UTIL.shutdownMiniCluster();
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    this.admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
+  }
+
+  /**
+   * Create two tables only on specific number of regionservers (subset of all
+   * regionservers). Check after the creation whether the regions are assigned
+   * only to those ones.
+   *
+   * @throws IOException
+   */
+  @Test
+  public void testCreateTableOnRegionServers() throws IOException {
+    byte[] tableName = Bytes.toBytes("testCreateTableWithRegionsOnServers");
+    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},
+    };
+    HTableDescriptor desc = new HTableDescriptor(tableName);
+    desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
+    List<HServerAddress> allServers = TEST_UTIL.getHBaseCluster().getRegionServers();
+    System.out.println("initial number of servers: " + allServers.size());
+    // remove some regionservers
+    for (int i = 0; i < NUM_REMOVED_RS; i++) {
+      allServers.remove(0);
+    }
+    // create a table on the remaining regionservers
+    // refresh Admin to pickup new configuration about using favored nodes
+    admin.createTable(desc, splitKeys, allServers);
+    HTable ht = new HTable(TEST_UTIL.getConfiguration(), tableName);
+    Map<HRegionInfo,HServerAddress> regions = ht.getRegionsInfo();
+    int expectedRegions = splitKeys.length + 1;
+    assertEquals("Tried to create " + expectedRegions + " regions " +
+        "but only found " + regions.size(),
+        expectedRegions, regions.size());
+     //verify if we use only a subset of the regionservers
+    Set<HServerAddress> serversForTable = new HashSet<HServerAddress>();
+    serversForTable.addAll(regions.values());
+    assertEquals(NUM_REGION_SERVER - NUM_REMOVED_RS, allServers.size());
+    assertEquals(allServers.size(), serversForTable.size());
+
+    // create one more table only on allServers
+    tableName = Bytes.toBytes("testCreateTableWithRegionsOnServers2");
+    byte[][] splitKeys2 = {
+        new byte[]{1, 1, 1},
+        new byte[]{2, 2, 2}
+    };
+    desc = new HTableDescriptor(tableName);
+    desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
+    admin.createTable(desc, splitKeys2, allServers);
+    ht = new HTable(TEST_UTIL.getConfiguration(), tableName);
+    regions = ht.getRegionsInfo();
+    expectedRegions = splitKeys2.length + 1;
+    assertEquals("Tried to create " + expectedRegions + " regions " +
+        "but only found " + regions.size(),
+        expectedRegions, regions.size());
+     //verify if we use only a subset of the regionservers
+    serversForTable = new HashSet<HServerAddress>();
+    serversForTable.addAll(regions.values());
+    assertEquals(NUM_REGION_SERVER - NUM_REMOVED_RS, allServers.size());
+    assertEquals(allServers.size(), serversForTable.size());
+  }
+}