You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ns...@apache.org on 2011/10/11 04:24:53 UTC

svn commit: r1181602 - /hbase/branches/0.89/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java

Author: nspiegelberg
Date: Tue Oct 11 02:24:52 2011
New Revision: 1181602

URL: http://svn.apache.org/viewvc?rev=1181602&view=rev
Log:
Fixed a bug that caused the createTable(splitKeys) to open regions asynchronously.

Summary: The code in createTable(splitKeys) should now make sure that all regions are opened before returning.

Task ID: #611387

Reviewers: kannan, nspiegelberg

Test Plan:
  To reproduce the bug in unit test:
    1. Add a delay (~1s) in the worker runnable that opens a region in HRegionServer.java if the region to open is not the first region.
    2. Run the unit test that creates a table with 1000 regions.
    3. A NoServerForRegionException should be thrown to indicate the bug (which was originally never caught in the "retry" block).

  The unit test should pass after applying the fix.

Modified:
    hbase/branches/0.89/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java

Modified: hbase/branches/0.89/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java?rev=1181602&r1=1181601&r2=1181602&view=diff
==============================================================================
--- hbase/branches/0.89/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java (original)
+++ hbase/branches/0.89/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java Tue Oct 11 02:24:52 2011
@@ -33,6 +33,7 @@ import org.apache.hadoop.hbase.MasterNot
 import org.apache.hadoop.hbase.RegionException;
 import org.apache.hadoop.hbase.RemoteExceptionHandler;
 import org.apache.hadoop.hbase.TableExistsException;
+import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.ipc.HMasterInterface;
 import org.apache.hadoop.hbase.ipc.HRegionInterface;
@@ -44,11 +45,13 @@ import org.apache.hadoop.io.Writable;
 import org.apache.hadoop.ipc.RemoteException;
 
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.NavigableMap;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Provides an interface to manage HBase database table metadata + general
@@ -229,7 +232,7 @@ public class HBaseAdmin {
    * and attempt-at-creation).
    * @throws IOException
    */
-  public void createTable(HTableDescriptor desc, byte [][] splitKeys)
+  public void createTable(final HTableDescriptor desc, byte [][] splitKeys)
   throws IOException {
     HTableDescriptor.isLegalTableName(desc.getName());
     if(splitKeys != null && splitKeys.length > 1) {
@@ -244,22 +247,52 @@ public class HBaseAdmin {
       }
     }
     createTableAsync(desc, splitKeys);
-    for (int tries = 0; tries < numRetries; tries++) {
-      try {
-        // Wait for new table to come on-line
-        connection.locateRegion(desc.getName(), HConstants.EMPTY_START_ROW);
-        break;
-
-      } catch (RegionException e) {
+    int numRegs = splitKeys == null ? 1 : splitKeys.length + 1;
+    int prevRegCount = 0;
+    for (int tries = 0; tries < numRetries; ++tries) {
+      // Wait for new table to come on-line
+      final AtomicInteger actualRegCount = new AtomicInteger(0);
+      MetaScannerVisitor visitor = new MetaScannerVisitor() {
+        @Override
+        public boolean processRow(Result rowResult) throws IOException {
+          HRegionInfo info = Writables.getHRegionInfo(
+              rowResult.getValue(HConstants.CATALOG_FAMILY,
+                  HConstants.REGIONINFO_QUALIFIER));
+          if (!(Bytes.equals(info.getTableDesc().getName(), desc.getName()))) {
+            return false;
+          }
+          String hostAndPort = null;
+          byte [] value = rowResult.getValue(HConstants.CATALOG_FAMILY,
+              HConstants.SERVER_QUALIFIER);
+          // Make sure that regions are assigned to server
+          if (value != null && value.length > 0) {
+            hostAndPort = Bytes.toString(value);
+          }
+          if (!(info.isOffline() || info.isSplit()) && hostAndPort != null) {
+            actualRegCount.incrementAndGet();
+          }
+          return true;
+        }
+      };
+      MetaScanner.metaScan(conf, visitor, desc.getName());
+      if (actualRegCount.get() != numRegs) {
         if (tries == numRetries - 1) {
-          // Ran out of tries
-          throw e;
+          throw new RegionOfflineException("Only " + actualRegCount.get() +
+              " of " + numRegs + " regions are online; retries exhausted.");
         }
-      }
-      try {
-        Thread.sleep(getPauseTime(tries));
-      } catch (InterruptedException e) {
-        // continue
+        try { // Sleep
+          Thread.sleep(getPauseTime(tries));
+        } catch (InterruptedException e) {
+          throw new InterruptedIOException("Interrupted when opening" +
+              " regions; " + actualRegCount.get() + " of " + numRegs +
+              " regions processed so far");
+        }
+        if (actualRegCount.get() > prevRegCount) { // Making progress
+          prevRegCount = actualRegCount.get();
+          tries = -1;
+        }
+      } else {
+        return;
       }
     }
   }