You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by mb...@apache.org on 2012/08/05 21:16:13 UTC

svn commit: r1369645 [1/3] - in /hbase/branches/0.89-fb: ./ src/main/java/org/apache/hadoop/hbase/ src/main/java/org/apache/hadoop/hbase/client/ src/main/java/org/apache/hadoop/hbase/executor/ src/main/java/org/apache/hadoop/hbase/master/ src/main/java...

Author: mbautin
Date: Sun Aug  5 19:16:11 2012
New Revision: 1369645

URL: http://svn.apache.org/viewvc?rev=1369645&view=rev
Log:
[master] [89-fb] Fix master failover

Summary:
To implement proper master failover, we need to:
-  Do log splitting as the first thing on cluster startup, so that we can split logs for ROOT and META before we assign them.
- Start queuing all updates to the ZK unassigned directory for .META. and user regions
- Assign out the root region
- Scan the ZK unassigned directory for OPENED and CLOSED records for .META. regions and update -ROOT- accordingly
- Drain the queue of ZK unassigned directory updates for .META. regions, process events (modify -ROOT-), and switch to real-time processing for .META.
- Do initial root scan
- Wait until .META. is fully assigned (need to process region server events in a loop similarly to the master's main loop)
- Scan the ZK unassigned directory for user regions and update .META. accordingly
- Drain the queue of ZK unassigned directory updates for user regions, process events (modify .META.), and switch to real-time processing for -ROOT-.

Test Plan:
- Run all unit tests
- Deploy to cluster, kill a regionserver, then the active master. Look at the logs.

Reviewers: pkhemani, kranganathan, liyintang, kannan

Reviewed By: kranganathan

Differential Revision: https://reviews.facebook.net/D2085

Added:
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/util/DrainableQueue.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/util/ParamCallable.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/zookeeper/LegacyRootZNodeUpdater.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/zookeeper/ZNodePathAndData.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/TestHServerInfo.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/util/TestDrainableQueue.java
Modified:
    hbase/branches/0.89-fb/pom.xml
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerAddress.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerInfo.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/KeyValue.java
    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/executor/HBaseEventHandler.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/BaseScanner.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/MetaScanner.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionOpen.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionStatusChange.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionManager.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionServerOperation.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RootScanner.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ZKClusterStateRecovery.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ZKUnassignedWatcher.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/handler/MasterCloseRegionHandler.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/handler/MasterOpenRegionHandler.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/wal/SequenceFileLogWriter.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/util/JVMClusterUtil.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/util/Threads.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/zookeeper/RecoverableZooKeeper.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperWrapper.java
    hbase/branches/0.89-fb/src/main/resources/hbase-default.xml
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/encoding/TestUpgradeFromHFileV1ToEncoding.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/mapreduce/TestTableMapReduce.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/MultiMasterTest.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/TestClusterStartupDetection.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/TestLogSplitOnMasterFailover.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/TestMasterFailover.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/TestRSLivenessOnMasterFailover.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/TestRegionStateOnMasterFailure.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionInfo.java

Modified: hbase/branches/0.89-fb/pom.xml
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/pom.xml?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/pom.xml (original)
+++ hbase/branches/0.89-fb/pom.xml Sun Aug  5 19:16:11 2012
@@ -229,7 +229,7 @@
           <version>2.8</version>
           <configuration>
             <forkedProcessTimeoutInSeconds>900</forkedProcessTimeoutInSeconds>
-            <argLine>-enableassertions -Xmx512m</argLine>
+            <argLine>-enableassertions -Xmx1024m</argLine>
             <redirectTestOutputToFile>true</redirectTestOutputToFile>
           </configuration>
         </plugin>

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java Sun Aug  5 19:16:11 2012
@@ -52,11 +52,11 @@ public class HRegionInfo extends Version
    * where,
    *    &lt;encodedName> is a hex version of the MD5 hash of
    *    &lt;tablename>,&lt;startkey>,&lt;regionIdTimestamp>
-   *
+   * 
    * The old region name format:
    *    &lt;tablename>,&lt;startkey>,&lt;regionIdTimestamp>
    * For region names in the old format, the encoded name is a 32-bit
-   * JenkinsHash integer value (in its decimal notation, string form).
+   * JenkinsHash integer value (in its decimal notation, string form). 
    *<p>
    * **NOTE**
    *
@@ -66,8 +66,8 @@ public class HRegionInfo extends Version
    */
 
   /** Separator used to demarcate the encodedName in a region name
-   * in the new format. See description on new format above.
-   */
+   * in the new format. See description on new format above. 
+   */ 
   private static final int ENC_SEPARATOR = '.';
   public  static final int MD5_HEX_LENGTH   = 32;
 
@@ -82,11 +82,11 @@ public class HRegionInfo extends Version
     if ((regionName.length >= 1)
         && (regionName[regionName.length - 1] == ENC_SEPARATOR)) {
       // region name is new format. it contains the encoded name.
-      return true;
+      return true; 
     }
     return false;
   }
-
+  
   /**
    * @param regionName
    * @return the encodedName
@@ -100,7 +100,7 @@ public class HRegionInfo extends Version
           regionName.length - MD5_HEX_LENGTH - 1,
           MD5_HEX_LENGTH);
     } else {
-      // old format region name. ROOT and first META region also
+      // old format region name. ROOT and first META region also 
       // use this format.EncodedName is the JenkinsHash value.
       int hashVal = Math.abs(JenkinsHash.getInstance().hash(regionName,
                                                             regionName.length,
@@ -117,6 +117,10 @@ public class HRegionInfo extends Version
   public static final HRegionInfo ROOT_REGIONINFO =
     new HRegionInfo(0L, HTableDescriptor.ROOT_TABLEDESC);
 
+  /** Encoded name for the root region. This is always the same. */
+  public static final String ROOT_REGION_ENCODED_NAME_STR =
+      HRegionInfo.ROOT_REGIONINFO.getEncodedName();
+
   /** HRegionInfo for first meta region */
   public static final HRegionInfo FIRST_META_REGIONINFO =
     new HRegionInfo(1L, HTableDescriptor.META_TABLEDESC);
@@ -153,8 +157,8 @@ public class HRegionInfo extends Version
     super();
     this.regionId = regionId;
     this.tableDesc = tableDesc;
-
-    // Note: Root & First Meta regions names are still in old format
+    
+    // Note: Root & First Meta regions names are still in old format   
     this.regionName = createRegionName(tableDesc.getName(), null,
                                        regionId, false);
     this.regionNameStr = Bytes.toStringBinary(this.regionName);
@@ -303,7 +307,7 @@ public class HRegionInfo extends Version
 
       if (md5HashBytes.length != MD5_HEX_LENGTH) {
         LOG.error("MD5-hash length mismatch: Expected=" + MD5_HEX_LENGTH +
-                  "; Got=" + md5HashBytes.length);
+                  "; Got=" + md5HashBytes.length); 
       }
 
       // now append the bytes '.<encodedName>.' to the end
@@ -312,7 +316,7 @@ public class HRegionInfo extends Version
       offset += MD5_HEX_LENGTH;
       b[offset++] = ENC_SEPARATOR;
     }
-
+    
     return b;
   }
 
@@ -331,8 +335,8 @@ public class HRegionInfo extends Version
         break;
       }
     }
-    if(offset == -1) {
-      throw new IOException("Invalid regionName format: " +
+    if(offset == -1) { 
+      throw new IOException("Invalid regionName format: " + 
                             Bytes.toStringBinary(regionName));
     }
     byte [] tableName = new byte[offset];
@@ -344,8 +348,8 @@ public class HRegionInfo extends Version
         break;
       }
     }
-    if(offset == -1) {
-      throw new IOException("Invalid regionName format: " +
+    if(offset == -1) { 
+      throw new IOException("Invalid regionName format: " + 
                             Bytes.toStringBinary(regionName));
     }
     byte [] startKey = HConstants.EMPTY_BYTE_ARRAY;
@@ -404,7 +408,7 @@ public class HRegionInfo extends Version
   public byte [] getStartKey(){
     return startKey;
   }
-
+  
   /** @return the endKey */
   public byte [] getEndKey(){
     return endKey;
@@ -430,7 +434,7 @@ public class HRegionInfo extends Version
       Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY);
     return firstKeyInRange && lastKeyInRange;
   }
-
+  
   /**
    * Return true if the given row falls in this region.
    */
@@ -485,7 +489,7 @@ public class HRegionInfo extends Version
    * @return point to explicitly split the region on
    */
   public byte[] getSplitPoint() {
-    return (this.splitPoint != null && this.splitPoint.length > 0)
+    return (this.splitPoint != null && this.splitPoint.length > 0) 
       ? this.splitPoint : null;
   }
 

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerAddress.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerAddress.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerAddress.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerAddress.java Sun Aug  5 19:16:11 2012
@@ -27,6 +27,7 @@ import java.net.InetSocketAddress;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.io.WritableComparable;
 
@@ -34,6 +35,9 @@ import org.apache.hadoop.io.WritableComp
  * HServerAddress is a "label" for a HBase server made of host and port number.
  */
 public class HServerAddress implements WritableComparable<HServerAddress> {
+
+  private static final Log LOG = LogFactory.getLog(HServerAddress.class);
+
   private InetSocketAddress address;
   private String stringValue;
   private String hostAddress;
@@ -108,7 +112,7 @@ public class HServerAddress implements W
     stringValue = other.stringValue;
     checkBindAddressCanBeResolved();
   }
-
+  
   /**
    * Get the normalized hostAddress:port as a string format
    * @param address
@@ -134,13 +138,12 @@ public class HServerAddress implements W
   public String getBindAddress() {
     if (this.hostAddress != null)
       return hostAddress;
-
+    
     final InetAddress addr = address.getAddress();
     if (addr != null) {
       return addr.getHostAddress();
     } else {
-      LogFactory.getLog(HServerAddress.class).error("Could not resolve the"
-          + " DNS name of " + stringValue);
+      LOG.error("Could not resolve the DNS name of " + stringValue);
       return null;
     }
   }

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerInfo.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerInfo.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerInfo.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/HServerInfo.java Sun Aug  5 19:16:11 2012
@@ -24,6 +24,7 @@ import java.io.DataOutput;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -31,7 +32,6 @@ import org.apache.hadoop.hbase.regionser
 import org.apache.hadoop.io.Writable;
 import org.apache.hadoop.io.WritableComparable;
 
-
 /**
  * HServerInfo is meta info about an {@link HRegionServer}.  It is the token
  * by which a master distingushes a particular regionserver from the rest.
@@ -53,7 +53,12 @@ public class HServerInfo implements Writ
    * its startcode. Servername is formatted as
    * <code>&lt;hostname> '{@ink #SERVERNAME_SEPARATOR"}' &lt;port> '{@ink #SERVERNAME_SEPARATOR"}' &lt;startcode></code>.
    */
-  private static final String SERVERNAME_SEPARATOR = ",";
+  static final String SERVERNAME_SEPARATOR = ",";
+
+  private static final Pattern SERVER_NAME_RE = Pattern.compile(
+      "^[^,]+" + SERVERNAME_SEPARATOR + 
+      "[0-9]{1," + String.valueOf(0xffff).length() + "}" + SERVERNAME_SEPARATOR +
+      "-?[0-9]{1," + String.valueOf(Long.MAX_VALUE).length() + "}");
 
   private HServerAddress serverAddress;
   private long startCode;
@@ -79,6 +84,16 @@ public class HServerInfo implements Writ
     this(serverAddress, System.currentTimeMillis(), hostname);
   }
 
+  /** Initializes from server address and start code. Used in unit tests. */
+  HServerInfo(HServerAddress serverAddress, long startCode) {
+    this(serverAddress, startCode, serverAddress.getHostname());
+  }
+
+  /** Auto-generates a start code. */
+  public HServerInfo(final HServerAddress serverAddress) {
+    this(serverAddress, 0, serverAddress.getHostname());
+  }
+
   public HServerInfo(HServerAddress serverAddress, long startCode, String hostname) {
     this.serverAddress = serverAddress;
     this.startCode = startCode;
@@ -288,4 +303,13 @@ public class HServerInfo implements Writ
 
     return new HServerInfo(new HServerAddress(hostName, port), startCode, hostName);
   }
+
+  public static boolean isValidServerName(String serverName) {
+    return SERVER_NAME_RE.matcher(serverName).matches();
+  }
+
+  public static HServerAddress getAddress(HServerInfo hsi) {
+    return hsi != null ? hsi.getServerAddress() : null;
+  }
+
 }

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/KeyValue.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/KeyValue.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/KeyValue.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/KeyValue.java Sun Aug  5 19:16:11 2012
@@ -1295,7 +1295,7 @@ public class KeyValue implements Writabl
       final int offset, final int length, final int delimiter) {
     int index = getDelimiter(b, offset, length, delimiter);
     if (index < 0) {
-      throw new IllegalArgumentException("No " + (char)delimiter + " in <" +
+      throw new IllegalArgumentException("No '" + (char)delimiter + "' in <" +
         Bytes.toString(b) + ">" + ", length=" + length + ", offset=" + offset);
     }
     return index;
@@ -1309,7 +1309,7 @@ public class KeyValue implements Writabl
       final int offset, final int length, final int delimiter) {
     int index = getDelimiterInReverse(b, offset, length, delimiter);
     if (index < 0) {
-      throw new IllegalArgumentException("No " + delimiter + " in <" +
+      throw new IllegalArgumentException("No '" + ((char) delimiter) + "' in <" +
         Bytes.toString(b) + ">" + ", length=" + length + ", offset=" + offset);
     }
     return index;

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=1369645&r1=1369644&r2=1369645&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 Sun Aug  5 19:16:11 2012
@@ -60,10 +60,10 @@ import org.apache.hadoop.ipc.RemoteExcep
 
 
 /**
- * Provides an interface to manage HBase database table metadata + general
- * administrative functions.  Use HBaseAdmin to create, drop, list, enable and
- * disable tables. Use it also to add and drop table column families.
- *
+ * Provides an interface to manage HBase database table metadata + general 
+ * administrative functions.  Use HBaseAdmin to create, drop, list, enable and 
+ * disable tables. Use it also to add and drop table column families. 
+ * 
  * See {@link HTable} to add, update, and delete data from an individual table.
  */
 public class HBaseAdmin {
@@ -284,14 +284,14 @@ public class HBaseAdmin {
       MetaScanner.metaScan(conf, visitor, desc.getName());
       if (actualRegCount.get() != numRegs) {
         if (tries == numRetries - 1) {
-          throw new RegionOfflineException("Only " + actualRegCount.get() +
+          throw new RegionOfflineException("Only " + actualRegCount.get() + 
               " of " + numRegs + " regions are online; retries exhausted.");
         }
         try { // Sleep
           Thread.sleep(getPauseTime(tries));
         } catch (InterruptedException e) {
           throw new InterruptedIOException("Interrupted when opening" +
-              " regions; " + actualRegCount.get() + " of " + numRegs +
+              " regions; " + actualRegCount.get() + " of " + numRegs + 
               " regions processed so far");
         }
         if (actualRegCount.get() > prevRegCount) { // Making progress
@@ -597,10 +597,10 @@ public class HBaseAdmin {
       List<Pair<String, HColumnDescriptor>> columnModifications,
       List<String> columnDeletions) throws IOException {
     // convert all of the strings to bytes and pass to the bytes method
-    List<Pair<byte [], HColumnDescriptor>> modificationsBytes =
+    List<Pair<byte [], HColumnDescriptor>> modificationsBytes = 
       new ArrayList<Pair<byte [], HColumnDescriptor>>(
           columnModifications.size());
-    List<byte []> deletionsBytes =
+    List<byte []> deletionsBytes = 
       new ArrayList<byte []>(columnDeletions.size());
 
     for(Pair<String, HColumnDescriptor> c : columnModifications) {
@@ -618,7 +618,7 @@ public class HBaseAdmin {
   /**
    * Batch alter a table. Only takes regions offline once and performs a single
    * update to .META.
-   * Any of the three lists can be null, in which case those types of
+   * Any of the three lists can be null, in which case those types of 
    * alterations will be ignored.
    * Asynchronous operation.
    *
@@ -647,7 +647,7 @@ public class HBaseAdmin {
   /**
    * Get the status of alter command - indicates how many regions have received
    * the updated schema Asynchronous operation.
-   *
+   * 
    * @param tableName
    *          name of the table to get the status of
    * @return List indicating the number of regions updated List.get(0) is the
@@ -687,7 +687,7 @@ public class HBaseAdmin {
    * @param column column descriptor of column to be added
    * @throws IOException if a remote or network exception occurs
    */
-  public void addColumn(final byte [] tableName, HColumnDescriptor column)
+  public void addColumn(final byte [] tableName, HColumnDescriptor column) 
   throws IOException {
     alterTable(tableName, Arrays.asList(column), null, null);
   }
@@ -714,7 +714,7 @@ public class HBaseAdmin {
    * @param columnName name of column to be deleted
    * @throws IOException if a remote or network exception occurs
    */
-  public void deleteColumn(final byte [] tableName,
+  public void deleteColumn(final byte [] tableName, 
       final byte [] columnName)
   throws IOException {
     alterTable(tableName, null, null, Arrays.asList(columnName));
@@ -732,7 +732,7 @@ public class HBaseAdmin {
       HColumnDescriptor descriptor)
   throws IOException {
     alterTable(Bytes.toBytes(tableName), null, Arrays.asList(
-          new Pair<byte [], HColumnDescriptor>(Bytes.toBytes(columnName),
+          new Pair<byte [], HColumnDescriptor>(Bytes.toBytes(columnName), 
             descriptor)), null);
   }
 
@@ -981,7 +981,7 @@ public class HBaseAdmin {
   throws IOException {
     modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_MAJOR_COMPACT);
   }
-
+  
   /**
    * Major compacts a column family within a region or table.
    * Asynchronous operation.
@@ -1036,7 +1036,7 @@ public class HBaseAdmin {
   }
 
   /**
-   * Split a table or an individual region.  Implicitly finds an optimal split
+   * Split a table or an individual region.  Implicitly finds an optimal split 
    * point.  Asynchronous operation.
    *
    * @param tableNameOrRegionName table to region to split
@@ -1045,7 +1045,7 @@ public class HBaseAdmin {
   public void split(final byte [] tableNameOrRegionName) throws IOException {
     modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_SPLIT);
   }
-
+  
   public void split(final String tableNameOrRegionName,
     final String splitPoint) throws IOException {
     split(Bytes.toBytes(tableNameOrRegionName), Bytes.toBytes(splitPoint));
@@ -1059,7 +1059,7 @@ public class HBaseAdmin {
    * @param splitPoint the explicit position to split on
    * @throws IOException if a remote or network exception occurs
    */
-  public void split(final byte [] tableNameOrRegionName,
+  public void split(final byte [] tableNameOrRegionName, 
       final byte [] splitPoint) throws IOException {
     if (tableNameOrRegionName == null) {
       throw new IllegalArgumentException("Pass a table name or region name");
@@ -1067,7 +1067,7 @@ public class HBaseAdmin {
     byte [] tableName = tableExists(tableNameOrRegionName)?
       tableNameOrRegionName: null;
     byte [] regionName = tableName == null? tableNameOrRegionName: null;
-    Object [] args = regionName == null?
+    Object [] args = regionName == null? 
       new byte [][] {splitPoint}: new byte [][] {regionName, splitPoint};
     modifyTable(tableName, HConstants.Modify.TABLE_EXPLICIT_SPLIT, args);
   }
@@ -1176,7 +1176,7 @@ public class HBaseAdmin {
       throw RemoteExceptionHandler.decodeRemoteException(e);
     }
   }
-
+  
   private static Writable toWritable(Object o) {
     if (o == null) {
       return null;
@@ -1204,6 +1204,7 @@ public class HBaseAdmin {
       throw new MasterNotRunningException("master has been shut down");
     }
     try {
+      // Shutdown the whole HBase cluster.
       this.master.shutdown();
     } catch (RemoteException e) {
       throw RemoteExceptionHandler.decodeRemoteException(e);
@@ -1214,7 +1215,7 @@ public class HBaseAdmin {
 
   /**
    * Stop the designated RegionServer for a restart.
-   *
+   * 
    * @param hsa
    *          the address of the RegionServer to stop
    * @throws IOException

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/executor/HBaseEventHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/executor/HBaseEventHandler.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/executor/HBaseEventHandler.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/executor/HBaseEventHandler.java Sun Aug  5 19:16:11 2012
@@ -19,6 +19,7 @@
  */
 package org.apache.hadoop.hbase.executor;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -26,24 +27,26 @@ import java.util.List;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.executor.HBaseExecutorService.HBaseExecutorServiceType;
+import org.apache.hadoop.hbase.master.ServerManager;
+import org.apache.hadoop.hbase.util.Writables;
 
 
 /**
- * Abstract base class for all HBase event handlers. Subclasses should
- * implement the process() method where the actual handling of the event
+ * Abstract base class for all HBase event handlers. Subclasses should 
+ * implement the process() method where the actual handling of the event 
  * happens.
- *
- * HBaseEventType is a list of ALL events (which also corresponds to messages -
- * either internal to one component or between components). The event type
- * names specify the component from which the event originated, and the
+ * 
+ * HBaseEventType is a list of ALL events (which also corresponds to messages - 
+ * either internal to one component or between components). The event type 
+ * names specify the component from which the event originated, and the 
  * component which is supposed to handle it.
- *
- * Listeners can listen to all the events by implementing the interface
- * HBaseEventHandlerListener, and by registering themselves as a listener. They
+ * 
+ * Listeners can listen to all the events by implementing the interface 
+ * HBaseEventHandlerListener, and by registering themselves as a listener. They 
  * will be called back before and after the process of every event.
- *
- * TODO: Rename HBaseEvent and HBaseEventType to EventHandler and EventType
- * after ZK refactor as it currently would clash with EventType from ZK and
+ * 
+ * TODO: Rename HBaseEvent and HBaseEventType to EventHandler and EventType 
+ * after ZK refactor as it currently would clash with EventType from ZK and 
  * make the code very confusing.
  */
 public abstract class HBaseEventHandler implements Runnable
@@ -53,16 +56,23 @@ public abstract class HBaseEventHandler 
   protected HBaseEventType eventType = HBaseEventType.NONE;
   // is this a region server or master?
   protected boolean isRegionServer;
-  // name of the server - this is needed for naming executors in case of tests
+  // name of the server - this is needed for naming executors in case of tests 
   // where region servers may be co-located.
   protected String serverName;
+
+  protected final String regionName;
+  protected final byte[] serializedData;
+  protected final ServerManager serverManager;
+
+  protected RegionTransitionEventData hbEventData;
+
   // listeners that are called before and after an event is processed
-  protected static List<HBaseEventHandlerListener> eventHandlerListeners =
-    Collections.synchronizedList(new ArrayList<HBaseEventHandlerListener>());
+  protected static List<HBaseEventHandlerListener> eventHandlerListeners = 
+    Collections.synchronizedList(new ArrayList<HBaseEventHandlerListener>());  
 
   /**
-   * This interface provides hooks to listen to various events received by the
-   * queue. A class implementing this can listen to the updates by calling
+   * This interface provides hooks to listen to various events received by the 
+   * queue. A class implementing this can listen to the updates by calling 
    * registerListener and stop receiving updates by calling unregisterListener
    */
   public interface HBaseEventHandlerListener {
@@ -82,29 +92,29 @@ public abstract class HBaseEventHandler 
    */
   public enum HBaseEventType {
     NONE (-1),
-    // Messages originating from RS (NOTE: there is NO direct communication from
+    // Messages originating from RS (NOTE: there is NO direct communication from 
     // RS to Master). These are a result of RS updates into ZK.
     RS2ZK_REGION_CLOSING      (1),   // RS is in process of closing a region
     RS2ZK_REGION_CLOSED       (2),   // RS has finished closing a region
     RS2ZK_REGION_OPENING      (3),   // RS is in process of opening a region
     RS2ZK_REGION_OPENED       (4),   // RS has finished opening a region
-
-    // Updates from master to ZK. This is done by the master and there is
+    
+    // Updates from master to ZK. This is done by the master and there is 
     // nothing to process by either Master or RS
     M2ZK_REGION_OFFLINE       (50);  // Master adds this region as offline in ZK
-
+    
     private final byte value;
-
+    
     /**
-     * Called by the HMaster. Returns a name of the executor service given an
-     * event type. Every event type has en entry - if the event should not be
+     * Called by the HMaster. Returns a name of the executor service given an 
+     * event type. Every event type has en entry - if the event should not be 
      * handled just add the NONE executor.
      * @return name of the executor service
      */
     public HBaseExecutorServiceType getMasterExecutorForEvent() {
       HBaseExecutorServiceType executorServiceType = null;
       switch(this) {
-
+      
       case RS2ZK_REGION_CLOSING:
       case RS2ZK_REGION_CLOSED:
         executorServiceType = HBaseExecutorServiceType.MASTER_CLOSEREGION;
@@ -114,31 +124,31 @@ public abstract class HBaseEventHandler 
       case RS2ZK_REGION_OPENED:
         executorServiceType = HBaseExecutorServiceType.MASTER_OPENREGION;
         break;
-
+        
       case M2ZK_REGION_OFFLINE:
         executorServiceType = HBaseExecutorServiceType.NONE;
         break;
-
+        
       default:
         throw new RuntimeException("Unhandled event type in the master.");
       }
-
+      
       return executorServiceType;
     }
 
     /**
-     * Called by the RegionServer. Returns a name of the executor service given an
-     * event type. Every event type has en entry - if the event should not be
+     * Called by the RegionServer. Returns a name of the executor service given an 
+     * event type. Every event type has en entry - if the event should not be 
      * handled just return a null executor name.
      * @return name of the event service
      */
     public static String getRSExecutorForEvent(String serverName) {
       throw new RuntimeException("Unsupported operation.");
     }
-
+    
     /**
-     * Start the executor service that handles the passed in event type. The
-     * server that starts these event executor services wants to handle these
+     * Start the executor service that handles the passed in event type. The 
+     * server that starts these event executor services wants to handle these 
      * event types.
      */
     public void startMasterExecutorService(String serverName) {
@@ -150,13 +160,13 @@ public abstract class HBaseEventHandler 
     }
 
     public static void startRSExecutorService() {
-
+      
     }
 
     HBaseEventType(int intValue) {
       this.value = (byte)intValue;
     }
-
+    
     public byte getByteValue() {
       return value;
     }
@@ -175,30 +185,30 @@ public abstract class HBaseEventHandler 
       }
     }
   }
-
+  
   /**
    * Default base class constructor.
-   *
-   * TODO: isRegionServer and serverName will go away once we do the HMaster
-   * refactor. We will end up passing a ServerStatus which should tell us both
-   * the name and if it is a RS or master.
    */
-  public HBaseEventHandler(boolean isRegionServer, String serverName, HBaseEventType eventType) {
+  public HBaseEventHandler(boolean isRegionServer, String serverName, HBaseEventType eventType,
+      String regionName, byte[] serializedData, ServerManager serverManager) {
     this.isRegionServer = isRegionServer;
     this.eventType = eventType;
     this.serverName = serverName;
+    this.regionName = regionName;
+    this.serializedData = serializedData;
+    this.serverManager = serverManager;
   }
-
+  
   /**
-   * This is a wrapper around process, used to update listeners before and after
-   * events are processed.
+   * This is a wrapper around process, used to update listeners before and after 
+   * events are processed. 
    */
   public void run() {
     // fire all beforeProcess listeners
     for(HBaseEventHandlerListener listener : eventHandlerListeners) {
       listener.beforeProcess(this);
     }
-
+    
     // call the main process function
     try {
       process();
@@ -208,32 +218,32 @@ public abstract class HBaseEventHandler 
 
     // fire all afterProcess listeners
     for(HBaseEventHandlerListener listener : eventHandlerListeners) {
-      LOG.debug("Firing " + listener.getClass().getName() +
+      LOG.debug("Firing " + listener.getClass().getName() + 
                 ".afterProcess event listener for event " + eventType);
       listener.afterProcess(this);
     }
   }
-
+  
   /**
-   * This method is the main processing loop to be implemented by the various
+   * This method is the main processing loop to be implemented by the various 
    * subclasses.
    */
   public abstract void process();
-
+  
   /**
    * Subscribe to updates before and after processing events
    */
   public static void registerListener(HBaseEventHandlerListener listener) {
     eventHandlerListeners.add(listener);
   }
-
+  
   /**
    * Stop receiving updates before and after processing events
    */
   public static void unregisterListener(HBaseEventHandlerListener listener) {
     eventHandlerListeners.remove(listener);
   }
-
+  
   public boolean isRegionServer() {
     return isRegionServer;
   }
@@ -246,7 +256,7 @@ public abstract class HBaseEventHandler 
     // TODO: check for isRegionServer here
     return eventType.getMasterExecutorForEvent();
   }
-
+  
   /**
    * Return the event type
    * @return
@@ -266,12 +276,36 @@ public abstract class HBaseEventHandler 
     }
     serviceType.getExecutor(serverName).submit(this);
   }
-
+  
   /**
-   * Executes this event object in the caller's thread. This is a synchronous
+   * Executes this event object in the caller's thread. This is a synchronous 
    * way of executing the event.
    */
   public void execute() {
     this.run();
   }
+
+  public String getRegionName() {
+    return regionName;
+  }
+
+  protected void ensureEventDataAvailable() {
+    if (hbEventData != null) {
+      return;
+    }
+
+    try {
+      hbEventData = new RegionTransitionEventData();
+      Writables.getWritable(serializedData, hbEventData);
+    } catch (IOException e) {
+      LOG.error("Could not deserialize additional args for region transition", e);
+      throw new RuntimeException(e);
+    }
+  }
+  
+  public String getRegionServerName() {
+    ensureEventDataAvailable();
+    return hbEventData.getRsName();
+  }
+
 }

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java Sun Aug  5 19:16:11 2012
@@ -22,14 +22,14 @@ import org.apache.hadoop.hbase.util.Thre
 import org.apache.hadoop.hbase.util.HasThread;
 
 /**
- * Manages the preferences for assigning regions to specific servers.
+ * Manages the preferences for assigning regions to specific servers. 
  * It get the assignment plan from scanning the META region and keep this
  * assignment plan updated.
- *
+ * 
  * The assignment manager executes the assignment plan by adding the regions
  * with its most favored live region server into the transient assignment.
  * Each transient assignment will be only valid for a configurable time
- * before expire. During these valid time, the region will only be assigned
+ * before expire. During these valid time, the region will only be assigned 
  * based on the transient assignment.
  *
  * All access to this class is thread-safe.
@@ -68,12 +68,12 @@ public class AssignmentManager {
    * favored region server list.
    */
   private AssignmentPlan assignmentPlan;
-
+  
   private final HMaster master;
   private final Configuration conf;
   private long millisecondDelay;
   private POSITION[] positions;
-
+  
   public AssignmentManager(HMaster master) {
     this.master = master;
     this.conf = master.getConfiguration();
@@ -142,7 +142,7 @@ public class AssignmentManager {
         // information may indicate that the server is in the process of
         // shutting down.
         if (info != null &&
-            !master.getServerManager().isDead(info.getServerName()) &&
+            !master.getServerManager().isDeadProcessingPending(info.getServerName()) &&
             master.getServerManager().getServersToServerInfo().get(info.getServerName()) != null) {
           LOG.info("Add a transient assignment from the assignment plan: "
               + " region " + region.getRegionNameAsString() + " to the "
@@ -171,7 +171,7 @@ public class AssignmentManager {
         }
         LOG.debug("Remove the transisent assignment: region " +
             region.getRegionNameAsString() + " to " +
-            server.getHostNameWithPort());
+            server.getHostNameWithPort()); 
         return true;
       }
       return false;

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/BaseScanner.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/BaseScanner.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/BaseScanner.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/BaseScanner.java Sun Aug  5 19:16:11 2012
@@ -24,7 +24,6 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -122,9 +121,6 @@ abstract class BaseScanner extends Chore
   private final boolean rootRegion;
   protected final HMaster master;
 
-  protected boolean initialScanComplete;
-
-  protected abstract boolean initialScan();
   protected abstract void maintenanceScan();
 
   // will use this variable to synchronize and make sure we aren't interrupted
@@ -138,17 +134,6 @@ abstract class BaseScanner extends Chore
         master);
     this.rootRegion = rootRegion;
     this.master = master;
-    this.initialScanComplete = false;
-  }
-
-  /** @return true if initial scan completed successfully */
-  public boolean isInitialScanComplete() {
-    return initialScanComplete;
-  }
-
-  @Override
-  protected boolean initialChore() {
-    return initialScan();
   }
 
   @Override
@@ -196,19 +181,19 @@ abstract class BaseScanner extends Chore
               HConstants.FAVOREDNODES_QUALIFIER);
           AssignmentManager assignmentManager =
             this.master.getRegionManager().getAssignmentManager();
-
+          
           if (favoredNodes != null) {
             // compare the update TS
-            long updateTimeStamp =
+            long updateTimeStamp = 
               values.getLastestTimeStamp(HConstants.CATALOG_FAMILY,
                 HConstants.FAVOREDNODES_QUALIFIER);
-            long lastUpdate =
+            long lastUpdate = 
               assignmentManager.getAssignmentPlanUpdateTimeStamp(region);
             if (lastUpdate < updateTimeStamp) {
               // need to update the persistent assignment
               List<HServerAddress> servers =
                 RegionPlacement.getFavoredNodesList(favoredNodes);
-              assignmentManager.updateAssignmentPlan(region,
+              assignmentManager.updateAssignmentPlan(region, 
                   servers, updateTimeStamp);
             }
           } else {
@@ -555,15 +540,18 @@ abstract class BaseScanner extends Chore
     return result;
   }
 
-  /*
-   * Check the passed region is assigned.  If not, add to unassigned.
-   * @param regionServer
-   * @param meta
-   * @param info
+  /**
+   * Check the passed region ('info') is assigned. This method re-reads the state of the region
+   * from the 'meta' region if it appears unassigned, because this information might be stale. If
+   * not, add to unassigned.
+   *
+   * @param regionServer the regionserver hosting the meta/root region
+   * @param meta the meta/root region of the given region
+   * @param info the region info for the region we are checking
    * @param hostnameAndPort hostname ':' port as it comes out of .META.
-   * @param startCode
-   * @param checkTwice should we check twice before adding a region
-   * to unassigned pool.
+   * @param startCode start code of the regionserver that this region is assigned to acording to
+   *          meta/root
+   * @param checkTwice should we check twice before adding a region to unassigned pool.
    * @throws IOException
    */
   protected void checkAssigned(final HRegionInterface regionServer,
@@ -596,14 +584,21 @@ abstract class BaseScanner extends Chore
        * a dead server. Regions that were on a dead server will get reassigned
        * by ProcessServerShutdown
        */
+
+      boolean processingServerAsDead = false;
+      if (serverName != null) {
+        synchronized (master.getServerManager().deadServerStatusLock) {
+          processingServerAsDead =
+              this.master.getServerManager().isDeadProcessingPending(serverName);
+          storedInfo = this.master.getServerManager().getServerInfo(serverName);
+        }
+      }
+
       if (info == null || info.isOffline() ||
         this.master.getRegionManager().regionIsInTransition(info.getRegionNameAsString()) ||
-          (serverName != null && this.master.getServerManager().isDead(serverName))) {
+          (serverName != null && processingServerAsDead)) {
         return;
       }
-      if (serverName != null) {
-        storedInfo = this.master.getServerManager().getServerInfo(serverName);
-      }
 
       // If we can't find the HServerInfo, then add it to the list of
       //  unassigned regions.
@@ -619,6 +614,9 @@ abstract class BaseScanner extends Chore
           // Now get the region assigned
           this.master.getRegionManager().setUnassigned(info, true);
         }
+      } else if (info.isMetaTable()) {
+        MetaRegion m = new MetaRegion(storedInfo.getServerAddress(), info);
+        master.getRegionManager().putMetaRegionOnline(m);
       }
     }
     if (tryAgain) {
@@ -639,7 +637,7 @@ abstract class BaseScanner extends Chore
    * Interrupt thread regardless of what it's doing
    */
   public void interruptAndStop() {
-    synchronized(scannerLock){
+    synchronized(scannerLock) {
       if (isAlive()) {
         stopThread();
         super.interrupt();

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=1369645&r1=1369644&r2=1369645&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 Sun Aug  5 19:16:11 2012
@@ -33,7 +33,6 @@ import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NavigableMap;
@@ -67,7 +66,6 @@ import org.apache.hadoop.hbase.HConstant
 import org.apache.hadoop.hbase.HConstants.Modify;
 import org.apache.hadoop.hbase.HMsg;
 import org.apache.hadoop.hbase.HRegionInfo;
-import org.apache.hadoop.hbase.HRegionLocation;
 import org.apache.hadoop.hbase.HServerAddress;
 import org.apache.hadoop.hbase.HServerInfo;
 import org.apache.hadoop.hbase.HTableDescriptor;
@@ -114,6 +112,7 @@ import org.apache.hadoop.hbase.util.Slee
 import org.apache.hadoop.hbase.util.Threads;
 import org.apache.hadoop.hbase.util.VersionInfo;
 import org.apache.hadoop.hbase.util.Writables;
+import org.apache.hadoop.hbase.zookeeper.LegacyRootZNodeUpdater;
 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWrapper;
 import org.apache.hadoop.io.MapWritable;
 import org.apache.hadoop.io.Text;
@@ -174,7 +173,9 @@ public class HMaster extends HasThread i
   // Metrics is set when we call run.
   private MasterMetrics metrics;
 
+  /** A lock used for serial log splitting */
   final Lock splitLogLock = new ReentrantLock();
+
   final boolean distributedLogSplitting;
   SplitLogManager splitLogManager;
 
@@ -188,7 +189,7 @@ public class HMaster extends HasThread i
   private final Sleeper sleeper;
   // Keep around for convenience.
   private final FileSystem fs;
-  // Is the fileystem ok?
+  // Is the filesystem ok?
   private volatile boolean fsOk = true;
   // The Path to the old logs dir
   private final Path oldLogDir;
@@ -199,12 +200,17 @@ public class HMaster extends HasThread i
   private final ServerConnection connection;
   private ServerManager serverManager;
   private RegionManager regionManager;
+  private ZKUnassignedWatcher unassignedWatcher;
 
   private long lastFragmentationQuery = -1L;
   private Map<String, Integer> fragmentation = null;
   private RegionServerOperationQueue regionServerOperationQueue;
 
-  /** True if this is the master that started the cluster. */
+  /**
+   * True if this is the master that started the cluster. We mostly use this for unit testing, as
+   * our master failover workflow does not depend on this anymore.
+   */
+  @Deprecated
   private boolean isClusterStartup;
 
   private long masterStartupTime = Long.MAX_VALUE;
@@ -220,14 +226,14 @@ public class HMaster extends HasThread i
   private volatile boolean isActiveMaster = false;
 
   public ThreadPoolExecutor logSplitThreadPool;
-
+  
   public RegionPlacementPolicy regionPlacement;
 
   /** Log directories split on startup for testing master failover */
   private List<String> logDirsSplitOnStartup;
 
   private boolean shouldAssignRegionsWithFavoredNodes = false;
-
+  
   /**
    * The number of dead server log split requests received. This is not
    * incremented during log splitting on startup. This field is never
@@ -270,7 +276,6 @@ public class HMaster extends HasThread i
     // the primary master has written the address to ZK. So this has to be done
     // before we race to write our address to zookeeper.
     initializeZooKeeper();
-    detectClusterStartup();
 
     this.numRetries =  conf.getInt("hbase.client.retries.number", 2);
     this.threadWakeFrequency = conf.getInt(HConstants.THREAD_WAKE_FREQUENCY,
@@ -338,7 +343,7 @@ public class HMaster extends HasThread i
 
     final String masterName = getServerName();
     // initialize the thread pool for non-distributed log splitting.
-    int maxSplitLogThread =
+    int maxSplitLogThread = 
       conf.getInt("hbase.master.splitLogThread.max", 1000);
     logSplitThreadPool = Threads.getBoundedCachedThreadPool(
         maxSplitLogThread, 30L, TimeUnit.SECONDS,
@@ -354,7 +359,7 @@ public class HMaster extends HasThread i
         });
 
     regionPlacement = new RegionPlacement(this.conf);
-
+    
     // Only read favored nodes if using the assignment-based load balancer.
     this.shouldAssignRegionsWithFavoredNodes = conf.getClass(
         HConstants.LOAD_BALANCER_IMPL, Object.class).equals(
@@ -391,6 +396,18 @@ public class HMaster extends HasThread i
     return shouldAssignRegionsWithFavoredNodes;
   }
 
+  void startZKUnassignedWatcher() throws IOException {
+    if (unassignedWatcher != null) {
+      LOG.error("ZK unassigned watcher already started", new Throwable());
+      return;
+    }
+
+    // Start the unassigned watcher - which will create the unassigned region
+    // in ZK. If ZK unassigned events happen before the initial scan of the ZK unassigned
+    // directory is complete, they will be queued for further processing.
+    unassignedWatcher = new ZKUnassignedWatcher(this);
+  }
+  
   /**
    * @return true if successfully became primary master
    */
@@ -402,8 +419,6 @@ public class HMaster extends HasThread i
       zooKeeperWrapper.close();
       return false;
     }
-
-    detectClusterStartup();
     isActiveMaster = true;
 
     synchronized(this) {
@@ -414,17 +429,6 @@ public class HMaster extends HasThread i
       new RegionServerOperationQueue(this.conf, serverManager,
           getClosedStatus());
 
-
-    // Start the unassigned watcher - which will create the unassigned region
-    // in ZK. This is needed before RegionManager() constructor tries to assign
-    // the root region.
-    try {
-      ZKUnassignedWatcher.start(this.conf, this);
-    } catch (IOException e) {
-      LOG.error("Failed to start ZK unassigned region watcher", e);
-      throw new RuntimeException(e);
-    }
-
     // start the "close region" executor service
     HBaseEventType.RS2ZK_REGION_CLOSED.startMasterExecutorService(
         address.toString());
@@ -447,10 +451,6 @@ public class HMaster extends HasThread i
     return true;
   }
 
-  public void detectClusterStartup() {
-    isClusterStartup = (zooKeeperWrapper.scanRSDirectory().size() == 0);
-  }
-
   public ThreadPoolExecutor getLogSplitThreadPool() {
     return this.logSplitThreadPool;
   }
@@ -522,10 +522,11 @@ public class HMaster extends HasThread i
   }
 
   /**
-   * Returns true if this master process was responsible for starting the
-   * cluster.
+   * Returns true if this master process was responsible for starting the cluster. Only used in
+   * unit tests.
    */
-  public boolean isClusterStartup() {
+  @Deprecated
+  boolean isClusterStartup() {
     return isClusterStartup;
   }
 
@@ -747,26 +748,68 @@ public class HMaster extends HasThread i
       return;
     }
 
-    if (closed.get()) {
-      LOG.info("Master is closing, not starting the main loop");
+    if (isStopped()) {
+      LOG.info("Master is shutting down, not starting the main loop");
       return;
     }
+
     MonitoredTask startupStatus =
       TaskMonitor.get().createStatus("Master startup");
     startupStatus.setDescription("Master startup");
     clusterStateRecovery = new ZKClusterStateRecovery(this, connection);
     try {
-      joinCluster();
-      initPreferredAssignment();
-      startupStatus.setStatus("Initializing master service threads");
-      startServiceThreads();
-      masterStartupTime = System.currentTimeMillis();
-      startupStatus.markComplete("Initialization successful");
+      if (!isStopped() && !shouldAssignRegionsWithFavoredNodes()) {
+        // This is only done if we are using the old mechanism for locality-based assignment
+        // not relying on the favored node functionality in HDFS.
+        initPreferredAssignment();
+      }
+
+      if (!isStopped()) {
+        clusterStateRecovery.registerLiveRegionServers();
+        isClusterStartup = clusterStateRecovery.isClusterStartup();  // for testing
+      }
+
+      if (!isStopped() || isClusterShutdownRequested()) {
+        // Start the server so that region servers are running before we start
+        // splitting logs and before we start assigning regions. XXX What will
+        // happen if master starts receiving requests before regions are assigned?
+        // NOTE: If the master bind port is 0 (e.g. in unit tests) we initialize the RPC server
+        // earlier and do nothing here.
+        // TODO: move this to startServiceThreads once we break the dependency of distributed log
+        // splitting on regionserver check-in.
+        initRpcServer(address);
+        rpcServer.start();
+      }
+
+      if (!isStopped()) {
+        splitLogAfterStartup();
+      }
+
+      if (!isStopped()) {
+        startZKUnassignedWatcher();
+      }
+
+      if (!isStopped()) {
+        startupStatus.setStatus("Initializing master service threads");
+        startServiceThreads();
+        masterStartupTime = System.currentTimeMillis();
+        startupStatus.markComplete("Initialization successful");
+      }
     } catch (IOException e) {
       LOG.fatal("Unhandled exception. Master quits.", e);
       startupStatus.cleanup();
+      zooKeeperWrapper.close();
       return;
     }
+
+    if (isStopped()) {
+      startupStatus.markComplete("Initialization aborted, shutting down");
+    }
+
+    if (!isStopped()) {
+      clusterStateRecovery.backgroundRecoverRegionStateFromZK();
+    }
+    
     try {
       /* Main processing loop */
       FINISHED: while (!this.closed.get()) {
@@ -804,6 +847,7 @@ public class HMaster extends HasThread i
     closed.set(true);
 
     startShutdown();
+    startupStatus.cleanup();
 
     if (clusterShutdownRequested.get()) {
       // Wait for all the remaining region servers to report in. Only doing
@@ -812,15 +856,12 @@ public class HMaster extends HasThread i
     }
     serverManager.joinThreads();
 
-    /*
-     * Clean up and close up shop
-     */
     if (this.infoServer != null) {
       LOG.info("Stopping infoServer");
       try {
         this.infoServer.stop();
       } catch (Exception ex) {
-        ex.printStackTrace();
+        LOG.error("Error stopping info server", ex);
       }
     }
     if (this.rpcServer != null) {
@@ -956,78 +997,29 @@ public class HMaster extends HasThread i
     return regionLocalityMap;
   }
 
-
-  /*
-   * Joins cluster.  Checks to see if this instance of HBase is fresh or the
-   * master was started following a failover. In the second case, it inspects
-   * the region server directory and gets their regions assignment.
-   */
-  private void joinCluster() throws IOException  {
-    LOG.debug("Checking cluster state...");
-
-    clusterStateRecovery.registerLiveRegionServers();
-
-    // Check if this is a fresh start of the cluster
-    if (clusterStateRecovery.liveRegionServersAtStartup().isEmpty()) {
-      LOG.debug("Master fresh start, proceeding with normal startup");
-      return;
+  private void startSplitLogManager() {
+    if (this.distributedLogSplitting) {
+      // splitLogManager must be started before starting rpcServer because
+      // region-servers dying will trigger log splitting
+      this.splitLogManager = new SplitLogManager(zooKeeperWrapper, conf,
+          getStopper(), address.toString());
+      this.splitLogManager.finishInitialization();
     }
-
-    // Failover case.
-    LOG.info("Master failover, ZK inspection begins...");
-    // only read the rootlocation if it is failover
-    HServerAddress rootLocation =
-      this.zooKeeperWrapper.readRootRegionLocation();
-    boolean isRootRegionAssigned = false;
-    Map <byte[], HRegionInfo> assignedRegions =
-      new HashMap<byte[], HRegionInfo>();
-    // We must:
-    // - contact every region server to add them to the regionservers list
-    // - get their current regions assignment
-    // TODO: Run in parallel?
-    for (String serverName : clusterStateRecovery.liveRegionServersAtStartup()) {
-      HServerAddress address = HServerInfo.fromServerName(serverName).getServerAddress();
-      HRegionInfo[] regions = null;
-      try {
-        HRegionInterface hri =
-          this.connection.getHRegionConnection(address, false);
-        HServerInfo info = hri.getHServerInfo();
-        LOG.debug("Inspection found server " + info.getServerName());
-        regions = hri.getRegionsAssignment();
-      } catch (IOException e) {
-        LOG.error("Failed contacting " + address.toString(), e);
-        continue;
-      }
-      for (HRegionInfo r: regions) {
-        if (r.isRootRegion()) {
-          this.connection.setRootRegionLocation(new HRegionLocation(r, rootLocation));
-          this.regionManager.setRootRegionLocation(rootLocation);
-          // Undo the unassign work in the RegionManager constructor
-          this.regionManager.removeRegion(r);
-          isRootRegionAssigned = true;
-        } else if (r.isMetaRegion()) {
-          MetaRegion m = new MetaRegion(new HServerAddress(address), r);
-          this.regionManager.addMetaRegionToScan(m);
-        }
-        assignedRegions.put(r.getRegionName(), r);
-      }
-    }
-    LOG.info("Inspection found " + assignedRegions.size() + " regions, " +
-      (isRootRegionAssigned ? "with -ROOT-" : "but -ROOT- was MIA"));
   }
 
-  /*
-   * Inspect the log directory to recover any log file without
-   * an active region server.
+  /**
+   * Inspect the log directory to recover any log file without an active region
+   * server.
    */
   private void splitLogAfterStartup() {
+    startSplitLogManager();
     boolean retrySplitting = !conf.getBoolean("hbase.hlog.split.skip.errors",
         HLog.SPLIT_SKIP_ERRORS_DEFAULT);
     List<String> serverNames = new ArrayList<String>();
     try {
       do {
-        if (this.clusterShutdownRequested.get()) {
-          LOG.warn("Cluster is shutting down, aborting log splitting");
+        if (isStopped()) {
+          LOG.warn("Master is shutting down, aborting log splitting");
           return;
         }
         try {
@@ -1053,7 +1045,7 @@ public class HMaster extends HasThread i
               serverNames.add(serverName);
             } else {
               LOG.info("Log folder " + status.getPath() +
-                  " belongs to an existing region server");
+                  " belongs to an existing region server, not splitting");
             }
           }
           logDirsSplitOnStartup = serverNames;
@@ -1070,7 +1062,7 @@ public class HMaster extends HasThread i
           checkFileSystem(false);
 
           try {
-            if (retrySplitting) {
+            if (retrySplitting && !isStopped()) {
               Thread.sleep(30000); //30s
             }
           } catch (InterruptedException e) {
@@ -1101,6 +1093,10 @@ public class HMaster extends HasThread i
     long splitTime = 0, splitLogSize = 0, splitCount = 0;
     List<Path> logDirs = new ArrayList<Path>();
     for (String serverName : serverNames) {
+      if (isStopped()) {
+        LOG.warn("Master is shutting down, stopping log directory scan");
+        return;
+      }
       Path logDir = new Path(this.rootdir,
           HLog.getHLogDirectoryName(serverName));
       // rename the directory so a rogue RS doesn't create more HLogs
@@ -1135,13 +1131,23 @@ public class HMaster extends HasThread i
       // it is ok to call handleDeadWorkers with "rsname.splitting". These
       // altered names will just get ignored
       for (String serverName : serverNames) {
+        if (isStopped()) {
+          LOG.warn("Master is shutting down, stopping distributed log " +
+              "splitting");
+          return;
+        }
         splitLogManager.handleDeadWorker(serverName);
       }
       splitLogManager.splitLogDistributed(logDirs);
     } else {
+      // Serial log splitting.
       // splitLogLock ensures that dead region servers' logs are processed
       // one at a time
       for (Path logDir : logDirs) {
+        if (isStopped()) {
+          LOG.warn("Master is shutting down, stopping serial log splitting");
+          return;
+        }
         this.splitLogLock.lock();
         try {
           HLog.splitLog(this.rootdir, logDir, oldLogDir, this.fs,
@@ -1189,24 +1195,9 @@ public class HMaster extends HasThread i
         this.infoServer.setAttribute(MASTER, this);
         this.infoServer.start();
       }
-      if (this.distributedLogSplitting) {
-        // splitLogManager must be started before starting rpcServer because
-        // region-servers dying will trigger log splitting
-        this.splitLogManager = new SplitLogManager(zooKeeperWrapper, conf,
-            getStopper(), address.toString());
-        this.splitLogManager.finishInitialization();
-      }
-      // Start the server so that region servers are running before we start
-      // splitting logs and before we start assigning regions. XXX What will
-      // happen if master starts receiving requests before regions are assigned?
-      // NOTE: If the master bind port is 0 (e.g. in unit tests) we initialize the RPC server
-      // earlier and do nothing here.
-      initRpcServer(this.address);
-      this.rpcServer.start();
       if (LOG.isDebugEnabled()) {
         LOG.debug("Started service threads");
       }
-      splitLogAfterStartup();
     } catch (IOException e) {
       if (e instanceof RemoteException) {
         try {
@@ -1215,14 +1206,19 @@ public class HMaster extends HasThread i
           LOG.warn("thread start", ex);
         }
       }
-      // Something happened during startup. Shut things down.
+      // Something happened during startup. Stop the entire HBase cluster
+      // without quiescing region servers.
       this.closed.set(true);
       LOG.error("Failed startup", e);
     }
   }
 
-  /*
+  /**
    * Start shutting down the master. This does NOT trigger a cluster shutdown.
+   * However, if cluster shutdown has been triggered, this will indicate that
+   * it is now OK to stop regionservers, as it sets the master to the "closed"
+   * state. Therefore, only call this on cluster shutdown when all region
+   * servers have been quiesced.
    */
   void startShutdown() {
     this.closed.set(true);
@@ -1317,7 +1313,7 @@ public class HMaster extends HasThread i
     stopped = true;
     stopReason = "cluster shutdown";
   }
-
+  
   /** Shutdown the cluster quickly, don't quiesce regionservers */
   private void shutdownClusterNow() {
     closed.set(true);
@@ -1465,7 +1461,7 @@ public class HMaster extends HasThread i
    * Get the assignment domain for the table.
    * Currently the domain would be generated by shuffling all the online
    * region servers.
-   *
+   * 
    * It would be easy to extend for the multi-tenancy in the future.
    * @param tableName
    * @return the assignment domain for the table.
@@ -1474,18 +1470,18 @@ public class HMaster extends HasThread i
     // Get all the online region servers
     List<HServerAddress> onlineRSList =
       this.serverManager.getOnlineRegionServerList();
-
+    
     // Shuffle the server list based on the tableName
     Random random = new Random(tableName.hashCode());
     Collections.shuffle(onlineRSList, random);
-
+    
     // Add the shuffled server list into the assignment domain
     AssignmentDomain domain = new AssignmentDomain(this.conf);
     domain.addServers(onlineRSList);
-
+    
     return domain;
   }
-
+  
   @Override
   public void deleteTable(final byte [] tableName) throws IOException {
     lockTable(tableName, "delete");
@@ -1906,8 +1902,7 @@ public class HMaster extends HasThread i
     return status;
   }
 
-  // TODO ryan rework this function
-  /*
+  /**
    * Get HRegionInfo from passed META map of row values.
    * Returns null if none found (and logs fact that expected COL_REGIONINFO
    * was missing).  Utility method used by scanners of META tables.
@@ -1924,6 +1919,9 @@ public class HMaster extends HasThread i
       StringBuilder sb =  new StringBuilder();
       NavigableMap<byte[], byte[]> infoMap =
         res.getFamilyMap(HConstants.CATALOG_FAMILY);
+      if (infoMap == null) {
+        return null;
+      }
       for (byte [] e: infoMap.keySet()) {
         if (sb.length() > 0) {
           sb.append(", ");
@@ -2239,7 +2237,7 @@ public class HMaster extends HasThread i
   public StoppableMaster getStopper() {
     return this;
   }
-
+  
   public StopStatus getClosedStatus() {
     return new StopStatus() {
       @Override
@@ -2249,4 +2247,8 @@ public class HMaster extends HasThread i
     };
   }
 
+  ZKUnassignedWatcher getUnassignedWatcher() {
+    return unassignedWatcher;
+  }
 }
+

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/MetaScanner.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/MetaScanner.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/MetaScanner.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/MetaScanner.java Sun Aug  5 19:16:11 2012
@@ -39,7 +39,7 @@ import java.util.concurrent.TimeUnit;
  */
 class MetaScanner extends BaseScanner {
   /** Initial work for the meta scanner is queued up here */
-  private volatile BlockingQueue<MetaRegion> metaRegionsToScan =
+  private final BlockingQueue<MetaRegion> metaRegionsToScan =
     new LinkedBlockingQueue<MetaRegion>();
 
   private final List<MetaRegion> metaRegionsToRescan =
@@ -59,7 +59,6 @@ class MetaScanner extends BaseScanner {
   // things should be back to normal.
   private boolean scanOneMetaRegion(MetaRegion region) {
     while (!this.master.isClosed() &&
-        !this.master.getRegionManager().isInitialRootScanComplete() &&
         this.master.getRegionManager().getRootRegionLocation() == null) {
       sleep();
     }
@@ -98,31 +97,6 @@ class MetaScanner extends BaseScanner {
   }
 
   @Override
-  protected boolean initialScan() {
-    MetaRegion region = null;
-    while (!this.master.isClosed() &&
-        (region == null && metaRegionsToScan.size() > 0) &&
-          !metaRegionsScanned()) {
-      try {
-        region = metaRegionsToScan.poll(this.master.getThreadWakeFrequency(),
-          TimeUnit.MILLISECONDS);
-      } catch (InterruptedException e) {
-        // continue
-      }
-      if (region == null && metaRegionsToRescan.size() != 0) {
-        region = metaRegionsToRescan.remove(0);
-      }
-      if (region != null) {
-        if (!scanOneMetaRegion(region)) {
-          metaRegionsToRescan.add(region);
-        }
-      }
-    }
-    initialScanComplete = true;
-    return true;
-  }
-
-  @Override
   protected void maintenanceScan() {
     List<MetaRegion> regions =
       this.master.getRegionManager().getListOfOnlineMetaRegions();
@@ -132,24 +106,19 @@ class MetaScanner extends BaseScanner {
       regionCount++;
     }
     LOG.info("All " + regionCount + " .META. region(s) scanned");
-    metaRegionsScanned();
+    notfiyAfterScan();
   }
 
   /*
    * Called by the meta scanner when it has completed scanning all meta
    * regions. This wakes up any threads that were waiting for this to happen.
-   * @param totalRows Total rows scanned.
-   * @param regionCount Count of regions in  .META. table.
-   * @return False if number of meta regions matches count of online regions.
    */
-  private synchronized boolean metaRegionsScanned() {
-    if (!this.master.getRegionManager().isInitialRootScanComplete() ||
-        this.master.getRegionManager().numMetaRegions() !=
-          this.master.getRegionManager().numOnlineMetaRegions()) {
-      return false;
+  private synchronized void notfiyAfterScan() {
+    if (this.master.getRegionManager().numMetaRegions() <=
+        this.master.getRegionManager().numOnlineMetaRegions()) {
+      // All meta regions are online.
+      notifyAll();
     }
-    notifyAll();
-    return true;
   }
 
   /**
@@ -159,9 +128,8 @@ class MetaScanner extends BaseScanner {
   synchronized boolean waitForMetaRegionsOrClose() {
     while (!this.master.isClosed()) {
       synchronized (master.getRegionManager()) {
-        if (this.master.getRegionManager().isInitialRootScanComplete() &&
-            this.master.getRegionManager().numMetaRegions() ==
-              this.master.getRegionManager().numOnlineMetaRegions()) {
+        if (this.master.getRegionManager().numMetaRegions() <=
+            this.master.getRegionManager().numOnlineMetaRegions()) {
           break;
         }
       }
@@ -180,4 +148,8 @@ class MetaScanner extends BaseScanner {
   void addMetaRegionToScan(MetaRegion m) {
     metaRegionsToScan.add(m);
   }
-}
\ No newline at end of file
+
+  public int getNumMetaRegionsToScan() {
+    return metaRegionsToScan.size();
+  }
+}

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionOpen.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionOpen.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionOpen.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionOpen.java Sun Aug  5 19:16:11 2012
@@ -46,10 +46,6 @@ public class ProcessRegionOpen extends P
   public ProcessRegionOpen(HMaster master, HServerInfo info,
       HRegionInfo regionInfo) {
     super(master, info.getServerName(), regionInfo);
-    if (info == null) {
-      throw new NullPointerException("HServerInfo cannot be null; " +
-        "hbase-958 debugging");
-    }
     this.serverInfo = info;
   }
 
@@ -67,61 +63,55 @@ public class ProcessRegionOpen extends P
       // is online.
       return RegionServerOperationResult.OPERATION_DELAYED;
     }
-    HRegionInterface server =
-        master.getServerConnection().getHRegionConnection(getMetaRegion().getServer());
-    LOG.info(regionInfo.getRegionNameAsString() + " open on " +
-      serverInfo.getServerName());
-
-    // Register the newly-available Region's location.
-    Put p = new Put(regionInfo.getRegionName());
-    p.add(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER,
-      Bytes.toBytes(serverInfo.getHostnamePort()));
-    p.add(HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER,
-      Bytes.toBytes(serverInfo.getStartCode()));
-    server.put(metaRegionName, p);
-    LOG.info("Updated row " + regionInfo.getRegionNameAsString() +
-      " in region " + Bytes.toString(metaRegionName) + " with startcode=" +
-      serverInfo.getStartCode() + ", server=" + serverInfo.getHostnamePort());
-    synchronized (master.getRegionManager()) {
+    writeToMeta(getMetaRegion());
+    RegionManager regionManager = master.getRegionManager();
+    synchronized (regionManager) {
       if (isMetaTable) {
         // It's a meta region.
         MetaRegion m =
             new MetaRegion(new HServerAddress(serverInfo.getServerAddress()),
                 regionInfo);
-        if (!master.getRegionManager().isInitialMetaScanComplete()) {
-          // Put it on the queue to be scanned for the first time.
-          if (LOG.isDebugEnabled()) {
-            LOG.debug("Adding " + m.toString() + " to regions to scan");
-          }
-          master.getRegionManager().addMetaRegionToScan(m);
-        } else {
-          // Add it to the online meta regions
-          if (LOG.isDebugEnabled()) {
-            LOG.debug("Adding to onlineMetaRegions: " + m.toString());
-          }
-          master.getRegionManager().putMetaRegionOnline(m);
-          // Interrupting the Meta Scanner sleep so that it can
-          // process regions right away
-          master.getRegionManager().metaScannerThread.triggerNow();
+        // Add it to the online meta regions
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Adding to onlineMetaRegions: " + m.toString());
         }
+        regionManager.putMetaRegionOnline(m);
+        // Interrupting the Meta Scanner sleep so that it can
+        // process regions right away
+        regionManager.metaScannerThread.triggerNow();
       }
       // If updated successfully, remove from pending list if the state
       // is consistent. For example, a disable could be called before the
       // synchronization.
-      if(master.getRegionManager().
-          isOfflined(regionInfo.getRegionNameAsString())) {
+      if (regionManager.isOfflined(regionInfo.getRegionNameAsString())) {
         LOG.warn("We opened a region while it was asked to be closed.");
         ZooKeeperWrapper zkWrapper =
             ZooKeeperWrapper.getInstance(master.getConfiguration(),
                 master.getZKWrapperName());
         zkWrapper.deleteUnassignedRegion(regionInfo.getEncodedName());
       } else {
-        master.getRegionManager().removeRegion(regionInfo);
+        regionManager.removeRegion(regionInfo);
       }
       return RegionServerOperationResult.OPERATION_SUCCEEDED;
     }
   }
 
+  void writeToMeta(MetaRegion region) throws IOException {
+    HRegionInterface server =
+        master.getServerConnection().getHRegionConnection(region.getServer());
+    LOG.info(regionInfo.getRegionNameAsString() + " open on " + serverInfo.getServerName());
+    // Register the newly-available Region's location.
+    Put p = new Put(regionInfo.getRegionName());
+    p.add(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER,
+        Bytes.toBytes(serverInfo.getHostnamePort()));
+    p.add(HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER,
+        Bytes.toBytes(serverInfo.getStartCode()));
+    server.put(region.getRegionName(), p);
+    LOG.info("Updated row " + regionInfo.getRegionNameAsString() + " in region "
+        + Bytes.toString(region.getRegionName()) + " with startcode=" + serverInfo.getStartCode()
+        + ", server=" + serverInfo.getHostnamePort());
+  }
+  
   @Override
   protected int getPriority() {
     return 0; // highest priority

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionStatusChange.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionStatusChange.java?rev=1369645&r1=1369644&r2=1369645&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionStatusChange.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ProcessRegionStatusChange.java Sun Aug  5 19:16:11 2012
@@ -52,8 +52,8 @@ abstract class ProcessRegionStatusChange
         available = false;
       }
     } else {
-      if (!master.getRegionManager().isInitialRootScanComplete() ||
-          !metaTableAvailable()) {
+      // This operation is for a user table. 
+      if (!metaTableAvailable()) {
         // The root region has not been scanned or the meta table is not
         // available so we can't proceed.
         available = false;
@@ -74,9 +74,13 @@ abstract class ProcessRegionStatusChange
         this.metaRegionName = this.metaRegion.getRegionName();
       }
     }
+    if (metaRegion == null) {
+      throw new NullPointerException("Could not identify meta region: " +
+          "isMetaTable=" + isMetaTable + ", regionInfo=" + regionInfo);
+    }
     return this.metaRegion;
   }
-
+  
   public HRegionInfo getRegionInfo() {
     return regionInfo;
   }