You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by jg...@apache.org on 2011/01/29 00:38:19 UTC

svn commit: r1064930 - in /hbase/trunk: ./ src/main/java/org/apache/hadoop/hbase/master/ src/test/java/org/apache/hadoop/hbase/client/

Author: jgray
Date: Fri Jan 28 23:38:19 2011
New Revision: 1064930

URL: http://svn.apache.org/viewvc?rev=1064930&view=rev
Log:
HBASE-3305  Allow round-robin distribution for table created with multiple regions (ted yu via jgray)

Modified:
    hbase/trunk/CHANGES.txt
    hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java
    hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
    hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java
    hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java

Modified: hbase/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hbase/trunk/CHANGES.txt?rev=1064930&r1=1064929&r2=1064930&view=diff
==============================================================================
--- hbase/trunk/CHANGES.txt (original)
+++ hbase/trunk/CHANGES.txt Fri Jan 28 23:38:19 2011
@@ -56,6 +56,8 @@ Release 0.91.0 - Unreleased
                server.join() method (Jeff Hammerbacher via Stack)
    HBASE-3437  Support Explict Split Points from the Shell
    HBASE-3433  KeyValue API to explicitly distinguish between deep & shallow copies
+   HBASE-3305  Allow round-robin distribution for table created with
+               multiple regions (ted yu via jgray)
 
 
   NEW FEATURES

Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java
URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java?rev=1064930&r1=1064929&r2=1064930&view=diff
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java (original)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java Fri Jan 28 23:38:19 2011
@@ -1183,6 +1183,28 @@ public class AssignmentManager extends Z
   }
 
   /**
+   * Assigns list of user regions in round-robin fashion, if any exist.
+   * <p>
+   * This is a synchronous call and will return once every region has been
+   * assigned.  If anything fails, an exception is thrown
+   * @throws InterruptedException
+   * @throws IOException
+   */
+  public void assignUserRegions(List<HRegionInfo> regions, List<HServerInfo> servers) throws IOException, InterruptedException {
+    if (regions == null)
+      return;
+    Map<HServerInfo, List<HRegionInfo>> bulkPlan = null;
+    // Generate a round-robin bulk assignment plan
+    bulkPlan = LoadBalancer.roundRobinAssignment(regions, servers);
+    LOG.info("Bulk assigning " + regions.size() + " region(s) round-robin across " +
+               servers.size() + " server(s)");
+    // Use fixed count thread pool assigning.
+    BulkAssigner ba = new BulkStartupAssigner(this.master, bulkPlan, this);
+    ba.bulkAssign();
+    LOG.info("Bulk assigning done");
+  }
+
+  /**
    * Assigns all user regions, if any exist.  Used during cluster startup.
    * <p>
    * This is a synchronous call and will return once every region has been
@@ -1209,9 +1231,9 @@ public class AssignmentManager extends Z
       // Reuse existing assignment info
       bulkPlan = LoadBalancer.retainAssignment(allRegions, servers);
     } else {
-      // Generate a round-robin bulk assignment plan
-      bulkPlan = LoadBalancer.roundRobinAssignment(
-          new ArrayList<HRegionInfo>(allRegions.keySet()), servers);
+      // assign regions in round-robin fashion
+      assignUserRegions(new ArrayList<HRegionInfo>(allRegions.keySet()), servers);
+      return;
     }
     LOG.info("Bulk assigning " + allRegions.size() + " region(s) across " +
       servers.size() + " server(s), retainAssignment=" + retainAssignment);

Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/HMaster.java?rev=1064930&r1=1064929&r2=1064930&view=diff
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/HMaster.java (original)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/HMaster.java Fri Jan 28 23:38:19 2011
@@ -25,6 +25,7 @@ import java.lang.reflect.InvocationTarge
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
@@ -848,9 +849,15 @@ implements HMasterInterface, HMasterRegi
       // 4. Close the new region to flush to disk.  Close log file too.
       region.close();
       region.getLog().closeAndDelete();
+    }
 
-      // 5. Trigger immediate assignment of this region
-      assignmentManager.assign(region.getRegionInfo(), true);
+    // 5. Trigger immediate assignment of the regions in round-robin fashion
+    List<HServerInfo> servers = serverManager.getOnlineServersList();
+    try {
+      this.assignmentManager.assignUserRegions(Arrays.asList(newRegions), servers);
+    } catch (InterruptedException ie) {
+      LOG.error("Caught " + ie + " during round-robin assignment");
+      throw new IOException(ie);
     }
 
     // 5. If sync, wait for assignment of regions

Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java
URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java?rev=1064930&r1=1064929&r2=1064930&view=diff
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java (original)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java Fri Jan 28 23:38:19 2011
@@ -378,13 +378,18 @@ public class LoadBalancer {
     int numServers = servers.size();
     int max = (int)Math.ceil((float)numRegions/numServers);
     int serverIdx = 0;
-    for(HServerInfo server : servers) {
+    if (numServers > 1) {
+      serverIdx = rand.nextInt(numServers);
+    }
+    int regionIdx = 0;
+    for (int j = 0; j < numServers; j++) {
+      HServerInfo server = servers.get((j+serverIdx) % numServers);
       List<HRegionInfo> serverRegions = new ArrayList<HRegionInfo>(max);
-      for(int i=serverIdx;i<regions.size();i+=numServers) {
-        serverRegions.add(regions.get(i));
+      for (int i=regionIdx; i<numRegions; i += numServers) {
+        serverRegions.add(regions.get(i % numRegions));
       }
       assignments.put(server, serverRegions);
-      serverIdx++;
+      regionIdx++;
     }
     return assignments;
   }

Modified: hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java
URL: http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java?rev=1064930&r1=1064929&r2=1064930&view=diff
==============================================================================
--- hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java (original)
+++ hbase/trunk/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java Fri Jan 28 23:38:19 2011
@@ -25,7 +25,10 @@ import static org.junit.Assert.assertFal
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -297,6 +300,27 @@ public class TestAdmin {
     }
   }
 
+  protected void verifyRoundRobinDistribution(HTable ht, int expectedRegions) throws IOException {
+    int numRS = ht.getCurrentNrHRS();
+    Map<HRegionInfo,HServerAddress> regions = ht.getRegionsInfo();
+    Map<HServerAddress, List<HRegionInfo>> server2Regions = new HashMap<HServerAddress, List<HRegionInfo>>();
+    for (Map.Entry<HRegionInfo,HServerAddress> entry : regions.entrySet()) {
+      HServerAddress server = entry.getValue();
+      List<HRegionInfo> regs = server2Regions.get(server);
+      if (regs == null) {
+        regs = new ArrayList<HRegionInfo>();
+        server2Regions.put(server, regs);
+      }
+      regs.add(entry.getKey());
+    }
+    float average = (float) expectedRegions/numRS;
+    int min = (int)Math.floor(average);
+    int max = (int)Math.ceil(average);
+    for (List<HRegionInfo> regionList : server2Regions.values()) {
+      assertTrue(regionList.size() == min || regionList.size() == max);
+    }
+  }
+
   @Test
   public void testCreateTableWithRegions() throws IOException, InterruptedException {
 
@@ -358,6 +382,8 @@ public class TestAdmin {
     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[8]));
     assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
 
+    verifyRoundRobinDistribution(ht, expectedRegions);
+
     // Now test using start/end with a number of regions
 
     // Use 80 bit numbers to make sure we aren't limited
@@ -415,6 +441,8 @@ public class TestAdmin {
     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {9,9,9,9,9,9,9,9,9,9}));
     assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
 
+    verifyRoundRobinDistribution(ht, expectedRegions);
+
     // Try once more with something that divides into something infinite
 
     startKey = new byte [] { 0, 0, 0, 0, 0, 0 };
@@ -436,6 +464,8 @@ public class TestAdmin {
         expectedRegions, regions.size());
     System.err.println("Found " + regions.size() + " regions");
 
+    verifyRoundRobinDistribution(ht, expectedRegions);
+
     // Try an invalid case where there are duplicate split keys
     splitKeys = new byte [][] {
         new byte [] { 1, 1, 1 },