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

svn commit: r1569861 - in /hbase/branches/hbase-10070: hbase-client/src/main/java/org/apache/hadoop/hbase/catalog/ hbase-client/src/main/java/org/apache/hadoop/hbase/client/ hbase-server/src/main/java/org/apache/hadoop/hbase/catalog/ hbase-server/src/m...

Author: ddas
Date: Wed Feb 19 18:05:54 2014
New Revision: 1569861

URL: http://svn.apache.org/r1569861
Log:
HBASE-10350. Master/AM/RegionStates changes to create and assign region replicas (ddas)

Added:
    hbase/branches/hbase-10070/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterOperationsForRegionReplicas.java
Modified:
    hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java
    hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
    hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionReplicaUtil.java
    hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/catalog/MetaEditor.java
    hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java
    hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
    hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RackManager.java
    hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java
    hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SnapshotOfRegionAssignmentFromMeta.java
    hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ModifyRegionUtils.java

Modified: hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java (original)
+++ hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java Wed Feb 19 18:05:54 2014
@@ -629,7 +629,8 @@ public class MetaReader {
    * @param replicaId the replicaId of the region
    * @return a byte[] for server column qualifier
    */
-  protected static byte[] getServerColumn(int replicaId) {
+  @VisibleForTesting
+  public static byte[] getServerColumn(int replicaId) {
     return replicaId == 0
         ? HConstants.SERVER_QUALIFIER
         : Bytes.toBytes(HConstants.SERVER_QUALIFIER_STR + META_REPLICA_ID_DELIMITER
@@ -641,7 +642,8 @@ public class MetaReader {
    * @param replicaId the replicaId of the region
    * @return a byte[] for server start code column qualifier
    */
-  protected static byte[] getStartCodeColumn(int replicaId) {
+  @VisibleForTesting
+  public static byte[] getStartCodeColumn(int replicaId) {
     return replicaId == 0
         ? HConstants.STARTCODE_QUALIFIER
         : Bytes.toBytes(HConstants.STARTCODE_QUALIFIER_STR + META_REPLICA_ID_DELIMITER
@@ -653,7 +655,8 @@ public class MetaReader {
    * @param replicaId the replicaId of the region
    * @return a byte[] for seqNum column qualifier
    */
-  protected static byte[] getSeqNumColumn(int replicaId) {
+  @VisibleForTesting
+  public static byte[] getSeqNumColumn(int replicaId) {
     return replicaId == 0
         ? HConstants.SEQNUM_QUALIFIER
         : Bytes.toBytes(HConstants.SEQNUM_QUALIFIER_STR + META_REPLICA_ID_DELIMITER

Modified: hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java (original)
+++ hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java Wed Feb 19 18:05:54 2014
@@ -39,6 +39,7 @@ import org.apache.hadoop.classification.
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.Abortable;
 import org.apache.hadoop.hbase.ClusterStatus;
+import org.apache.hadoop.hbase.RegionLocations;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HBaseIOException;
@@ -500,7 +501,7 @@ public class HBaseAdmin implements Abort
     } catch (SocketTimeoutException ste) {
       LOG.warn("Creating " + desc.getTableName() + " took too long", ste);
     }
-    int numRegs = splitKeys == null ? 1 : splitKeys.length + 1;
+    int numRegs = (splitKeys == null ? 1 : splitKeys.length + 1) * desc.getRegionReplication();
     int prevRegCount = 0;
     boolean doneWithMetaScan = false;
     for (int tries = 0; tries < this.numRetries * this.retryLongerMultiplier;
@@ -511,19 +512,27 @@ public class HBaseAdmin implements Abort
         MetaScannerVisitor visitor = new MetaScannerVisitorBase() {
           @Override
           public boolean processRow(Result rowResult) throws IOException {
-            HRegionInfo info = HRegionInfo.getHRegionInfo(rowResult);
-            if (info == null) {
+            RegionLocations list = MetaReader.getRegionLocations(rowResult);
+            if (list == null) {
               LOG.warn("No serialized HRegionInfo in " + rowResult);
               return true;
             }
-            if (!info.getTable().equals(desc.getTableName())) {
+            HRegionLocation l = list.getRegionLocation();
+            if (l == null) {
+              return true;
+            }
+            if (!l.getRegionInfo().getTable().equals(desc.getTableName())) {
               return false;
             }
-            ServerName serverName = HRegionInfo.getServerName(rowResult);
-            // Make sure that regions are assigned to server
-            if (!(info.isOffline() || info.isSplit()) && serverName != null
-                && serverName.getHostAndPort() != null) {
-              actualRegCount.incrementAndGet();
+            if (l.getRegionInfo().isOffline() || l.getRegionInfo().isSplit()) return true;
+            HRegionLocation[] locations = list.getRegionLocations();
+            for (HRegionLocation location : locations) {
+              if (location == null) continue;
+              ServerName serverName = location.getServerName();
+              // Make sure that regions are assigned to server
+              if (serverName != null && serverName.getHostAndPort() != null) {
+                actualRegCount.incrementAndGet();
+              }
             }
             return true;
           }

Modified: hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionReplicaUtil.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionReplicaUtil.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionReplicaUtil.java (original)
+++ hbase/branches/hbase-10070/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionReplicaUtil.java Wed Feb 19 18:05:54 2014
@@ -62,7 +62,13 @@ public class RegionReplicaUtil {
     return getRegionInfoForReplica(regionInfo, DEFAULT_REPLICA_ID);
   }
 
+  /** @return true if this replicaId corresponds to default replica for the region */
   public static boolean isDefaultReplica(int replicaId) {
     return DEFAULT_REPLICA_ID == replicaId;
   }
+
+  /** @return true if this region is a default replica for the region */
+  public static boolean isDefaultReplica(HRegionInfo hri) {
+    return  hri.getReplicaId() == DEFAULT_REPLICA_ID;
+  }
 }

Modified: hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/catalog/MetaEditor.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/catalog/MetaEditor.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/catalog/MetaEditor.java (original)
+++ hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/catalog/MetaEditor.java Wed Feb 19 18:05:54 2014
@@ -34,6 +34,7 @@ import org.apache.hadoop.hbase.client.De
 import org.apache.hadoop.hbase.client.HTable;
 import org.apache.hadoop.hbase.client.Mutation;
 import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.RegionReplicaUtil;
 import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType;
@@ -270,7 +271,9 @@ public class MetaEditor extends MetaRead
   throws IOException {
     List<Put> puts = new ArrayList<Put>();
     for (HRegionInfo regionInfo : regionInfos) {
-      puts.add(makePutFromRegionInfo(regionInfo));
+      if (RegionReplicaUtil.isDefaultReplica(regionInfo)) {
+        puts.add(makePutFromRegionInfo(regionInfo));
+      }
     }
     putsToMetaTable(catalogTracker, puts);
     LOG.info("Added " + puts.size());

Modified: hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java (original)
+++ hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java Wed Feb 19 18:05:54 2014
@@ -48,6 +48,8 @@ import org.apache.hadoop.hbase.Chore;
 import org.apache.hadoop.hbase.HBaseIOException;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.NotServingRegionException;
 import org.apache.hadoop.hbase.RegionTransition;
 import org.apache.hadoop.hbase.Server;
@@ -57,6 +59,7 @@ import org.apache.hadoop.hbase.TableName
 import org.apache.hadoop.hbase.TableNotFoundException;
 import org.apache.hadoop.hbase.catalog.CatalogTracker;
 import org.apache.hadoop.hbase.catalog.MetaReader;
+import org.apache.hadoop.hbase.client.RegionReplicaUtil;
 import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.exceptions.DeserializationException;
 import org.apache.hadoop.hbase.executor.EventHandler;
@@ -2553,19 +2556,50 @@ public class AssignmentManager extends Z
     boolean retainAssignment = server.getConfiguration().
       getBoolean("hbase.master.startup.retainassign", true);
 
+    Set<HRegionInfo> regionsFromMetaScan = allRegions.keySet();
     if (retainAssignment) {
       assign(allRegions);
     } else {
-      List<HRegionInfo> regions = new ArrayList<HRegionInfo>(allRegions.keySet());
+      List<HRegionInfo> regions = new ArrayList<HRegionInfo>(regionsFromMetaScan);
       assign(regions);
     }
 
-    for (HRegionInfo hri : allRegions.keySet()) {
+    for (HRegionInfo hri : regionsFromMetaScan) {
       TableName tableName = hri.getTable();
       if (!zkTable.isEnabledTable(tableName)) {
         setEnabledTable(tableName);
       }
     }
+    // assign all the replicas that were not recorded in the meta
+    assign(replicaRegionsNotRecordedInMeta(regionsFromMetaScan, (MasterServices)server));
+  }
+
+  /**
+   * Get a list of replica regions that are:
+   * not recorded in meta yet. We might not have recorded the locations
+   * for the replicas since the replicas may not have been online yet, master restarted
+   * in the middle of assigning, ZK erased, etc.
+   * @param regionsRecordedInMeta the list of regions we know are recorded in meta
+   * either as a default, or, as the location of a replica
+   * @param master
+   * @return list of replica regions
+   * @throws IOException
+   */
+  public static List<HRegionInfo> replicaRegionsNotRecordedInMeta(
+      Set<HRegionInfo> regionsRecordedInMeta, MasterServices master)throws IOException {
+    List<HRegionInfo> regionsNotRecordedInMeta = new ArrayList<HRegionInfo>();
+    for (HRegionInfo hri : regionsRecordedInMeta) {
+      TableName table = hri.getTable();
+      HTableDescriptor htd = master.getTableDescriptors().get(table);
+      // look at the HTD for the replica count. That's the source of truth
+      int desiredRegionReplication = htd.getRegionReplication();
+      for (int i = 0; i < desiredRegionReplication; i++) {
+        HRegionInfo replica = RegionReplicaUtil.getRegionInfoForReplica(hri, i);
+        if (regionsRecordedInMeta.contains(replica)) continue;
+        regionsNotRecordedInMeta.add(replica);
+      }
+    }
+    return regionsNotRecordedInMeta;
   }
 
   /**
@@ -2617,62 +2651,66 @@ public class AssignmentManager extends Z
       new TreeMap<ServerName, List<HRegionInfo>>();
     // Iterate regions in META
     for (Result result : results) {
-      Pair<HRegionInfo, ServerName> region = HRegionInfo.getHRegionInfoAndServerName(result);
-      if (region == null) continue;
-      HRegionInfo regionInfo = region.getFirst();
-      ServerName regionLocation = region.getSecond();
-      if (regionInfo == null) continue;
-      regionStates.createRegionState(regionInfo);
-      if (regionStates.isRegionInState(regionInfo, State.SPLIT)) {
-        // Split is considered to be completed. If the split znode still
-        // exists, the region will be put back to SPLITTING state later
-        LOG.debug("Region " + regionInfo.getRegionNameAsString()
-           + " split is completed. Hence need not add to regions list");
-        continue;
-      }
-      TableName tableName = regionInfo.getTable();
-      if (regionLocation == null) {
-        // regionLocation could be null if createTable didn't finish properly.
-        // When createTable is in progress, HMaster restarts.
-        // Some regions have been added to hbase:meta, but have not been assigned.
-        // When this happens, the region's table must be in ENABLING state.
-        // It can't be in ENABLED state as that is set when all regions are
-        // assigned.
-        // It can't be in DISABLING state, because DISABLING state transitions
-        // from ENABLED state when application calls disableTable.
-        // It can't be in DISABLED state, because DISABLED states transitions
-        // from DISABLING state.
-        if (!enablingTables.contains(tableName)) {
-          LOG.warn("Region " + regionInfo.getEncodedName() +
-            " has null regionLocation." + " But its table " + tableName +
-            " isn't in ENABLING state.");
-        }
-      } else if (!onlineServers.contains(regionLocation)) {
-        // Region is located on a server that isn't online
-        List<HRegionInfo> offlineRegions = offlineServers.get(regionLocation);
-        if (offlineRegions == null) {
-          offlineRegions = new ArrayList<HRegionInfo>(1);
-          offlineServers.put(regionLocation, offlineRegions);
-        }
-        offlineRegions.add(regionInfo);
-        // need to enable the table if not disabled or disabling or enabling
-        // this will be used in rolling restarts
-        if (!disabledOrDisablingOrEnabling.contains(tableName)
-            && !getZKTable().isEnabledTable(tableName)) {
-          setEnabledTable(tableName);
+      HRegionInfo regionInfo;
+      HRegionLocation[] locations = MetaReader.getRegionLocations(result).getRegionLocations();
+      if (locations == null) continue;
+      // Do the operations for all the replicas
+      for (HRegionLocation hrl : locations) {
+        if (hrl == null) continue;
+        ServerName regionLocation = hrl.getServerName();
+        regionInfo = hrl.getRegionInfo();
+        regionStates.createRegionState(regionInfo);
+        if (regionStates.isRegionInState(regionInfo, State.SPLIT)) {
+          // Split is considered to be completed. If the split znode still
+          // exists, the region will be put back to SPLITTING state later
+          LOG.debug("Region " + regionInfo.getRegionNameAsString()
+              + " split is completed. Hence need not add to regions list");
+          continue;
         }
-      } else {
-        // Region is being served and on an active server
-        // add only if region not in disabled or enabling table
-        if (!disabledOrEnablingTables.contains(tableName)) {
-          regionStates.updateRegionState(regionInfo, State.OPEN, regionLocation);
-          regionStates.regionOnline(regionInfo, regionLocation);
-        }
-        // need to enable the table if not disabled or disabling or enabling
-        // this will be used in rolling restarts
-        if (!disabledOrDisablingOrEnabling.contains(tableName)
-            && !getZKTable().isEnabledTable(tableName)) {
-          setEnabledTable(tableName);
+        TableName tableName = regionInfo.getTable();
+        if (regionLocation == null) {
+          // regionLocation could be null if createTable didn't finish properly.
+          // When createTable is in progress, HMaster restarts.
+          // Some regions have been added to hbase:meta, but have not been assigned.
+          // When this happens, the region's table must be in ENABLING state.
+          // It can't be in ENABLED state as that is set when all regions are
+          // assigned.
+          // It can't be in DISABLING state, because DISABLING state transitions
+          // from ENABLED state when application calls disableTable.
+          // It can't be in DISABLED state, because DISABLED states transitions
+          // from DISABLING state.
+          if (!enablingTables.contains(tableName)) {
+            LOG.warn("Region " + regionInfo.getEncodedName() +
+                " has null regionLocation." + " But its table " + tableName +
+                " isn't in ENABLING state.");
+          }
+        } else if (!onlineServers.contains(regionLocation)) {
+          // Region is located on a server that isn't online
+          List<HRegionInfo> offlineRegions = offlineServers.get(regionLocation);
+          if (offlineRegions == null) {
+            offlineRegions = new ArrayList<HRegionInfo>(1);
+            offlineServers.put(regionLocation, offlineRegions);
+          }
+          offlineRegions.add(regionInfo);
+          // need to enable the table if not disabled or disabling or enabling
+          // this will be used in rolling restarts
+          if (!disabledOrDisablingOrEnabling.contains(tableName)
+              && !getZKTable().isEnabledTable(tableName)) {
+            setEnabledTable(tableName);
+          }
+        } else {
+          // Region is being served and on an active server
+          // add only if region not in disabled or enabling table
+          if (!disabledOrEnablingTables.contains(tableName)) {
+            regionStates.updateRegionState(regionInfo, State.OPEN, regionLocation);
+            regionStates.regionOnline(regionInfo, regionLocation);
+          }
+          // need to enable the table if not disabled or disabling or enabling
+          // this will be used in rolling restarts
+          if (!disabledOrDisablingOrEnabling.contains(tableName)
+              && !getZKTable().isEnabledTable(tableName)) {
+            setEnabledTable(tableName);
+          }
         }
       }
     }
@@ -3522,4 +3560,8 @@ public class AssignmentManager extends Z
   public LoadBalancer getBalancer() {
     return this.balancer;
   }
+
+  public Map<ServerName, List<HRegionInfo>> getSnapShotOfAssignment(List<HRegionInfo> infos) {
+    return getRegionStates().getRegionAssignments(infos);
+  }
 }

Modified: hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java (original)
+++ hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java Wed Feb 19 18:05:54 2014
@@ -1787,18 +1787,30 @@ MasterServices, Server {
   private HRegionInfo[] getHRegionInfos(HTableDescriptor hTableDescriptor,
     byte[][] splitKeys) {
     HRegionInfo[] hRegionInfos = null;
+    int numRegionReplicas = hTableDescriptor.getRegionReplication();
+    if (numRegionReplicas <= 0) {
+      LOG.warn("Invalid number of replicas per region in the table descriptor. Setting it to 1.");
+      numRegionReplicas = 1;
+    }
+    long regionId = System.currentTimeMillis();
     if (splitKeys == null || splitKeys.length == 0) {
-      hRegionInfos = new HRegionInfo[]{
-          new HRegionInfo(hTableDescriptor.getTableName(), null, null)};
+      hRegionInfos = new HRegionInfo[numRegionReplicas];
+      for (int i = 0; i < numRegionReplicas; i++) {
+        hRegionInfos[i] = new HRegionInfo(hTableDescriptor.getTableName(), null, null,
+                false, regionId, (short)i);
+      }
     } else {
       int numRegions = splitKeys.length + 1;
-      hRegionInfos = new HRegionInfo[numRegions];
+      hRegionInfos = new HRegionInfo[numRegions * numRegionReplicas];
       byte[] startKey = null;
       byte[] endKey = null;
       for (int i = 0; i < numRegions; i++) {
         endKey = (i == splitKeys.length) ? null : splitKeys[i];
-        hRegionInfos[i] =
-            new HRegionInfo(hTableDescriptor.getTableName(), startKey, endKey);
+        for (int j = 0; j < numRegionReplicas; j++) {
+          hRegionInfos[i*numRegionReplicas + j] =
+               new HRegionInfo(hTableDescriptor.getTableName(), startKey, endKey,
+                   false, regionId, (short)j);
+        }
         startKey = endKey;
       }
     }

Modified: hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RackManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RackManager.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RackManager.java (original)
+++ hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RackManager.java Wed Feb 19 18:05:54 2014
@@ -17,6 +17,7 @@
  */
 package org.apache.hadoop.hbase.master;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -66,4 +67,20 @@ public class RackManager {
 
     return UNKNOWN_RACK;
   }
+
+  /**
+   * Same as {@link #getRack(ServerName)} except that a list is passed
+   * @param servers
+   * @return
+   */
+  public List<String> getRack(List<ServerName> servers) {
+    // just a note - switchMapping caches results (at least the implementation should unless the
+    // resolution is really a lightweight process)
+    List<String> serversAsString = new ArrayList<String>(servers.size());
+    for (ServerName server : servers) {
+      serversAsString.add(server.getHostname());
+    }
+    List<String> racks = switchMapping.resolve(serversAsString);
+    return racks;
+  }
 }

Modified: hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java (original)
+++ hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java Wed Feb 19 18:05:54 2014
@@ -38,6 +38,7 @@ import org.apache.hadoop.hbase.ServerLoa
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.catalog.MetaReader;
+import org.apache.hadoop.hbase.client.RegionReplicaUtil;
 import org.apache.hadoop.hbase.master.RegionState.State;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.Pair;
@@ -75,6 +76,11 @@ public class RegionStates {
   private final Map<ServerName, Set<HRegionInfo>> serverHoldings;
 
   /**
+   * Maintains the mapping from the default region to the replica regions.
+   */
+  private final Map<HRegionInfo, Set<HRegionInfo>> defaultReplicaToOtherReplicas;
+
+  /**
    * Region to server assignment map.
    * Contains the server a given region is currently assigned to.
    */
@@ -120,6 +126,7 @@ public class RegionStates {
     regionStates = new HashMap<String, RegionState>();
     regionsInTransition = new HashMap<String, RegionState>();
     serverHoldings = new HashMap<ServerName, Set<HRegionInfo>>();
+    defaultReplicaToOtherReplicas = new HashMap<HRegionInfo, Set<HRegionInfo>>();
     regionAssignments = new TreeMap<HRegionInfo, ServerName>();
     lastAssignments = new HashMap<String, ServerName>();
     processedServers = new HashMap<ServerName, Long>();
@@ -136,6 +143,43 @@ public class RegionStates {
     return (Map<HRegionInfo, ServerName>)regionAssignments.clone();
   }
 
+  /**
+   * Return the replicas (including default) for the regions grouped by ServerName
+   * @param regions
+   * @return a pair containing the groupings as a map
+   */
+  synchronized Map<ServerName, List<HRegionInfo>> getRegionAssignments(List<HRegionInfo> regions) {
+    Map<ServerName, List<HRegionInfo>> map = new HashMap<ServerName, List<HRegionInfo>>();
+    for (HRegionInfo region : regions) {
+      HRegionInfo defaultReplica = RegionReplicaUtil.getRegionInfoForDefaultReplica(region);
+      ServerName server = regionAssignments.get(defaultReplica);
+      List<HRegionInfo> regionsOnServer;
+      if (server != null) {
+        regionsOnServer = map.get(server);
+        if (regionsOnServer == null) {
+          regionsOnServer = new ArrayList<HRegionInfo>(1);
+          map.put(server, regionsOnServer);
+        }
+        regionsOnServer.add(defaultReplica);
+      }
+      Set<HRegionInfo> allReplicas = defaultReplicaToOtherReplicas.get(defaultReplica);
+      if (allReplicas != null) {
+        for (HRegionInfo hri : allReplicas) {
+          server = regionAssignments.get(hri);
+          if (server != null) { 
+            regionsOnServer = map.get(server);
+            if (regionsOnServer == null) {
+              regionsOnServer = new ArrayList<HRegionInfo>(1);
+              map.put(server, regionsOnServer);
+            }
+            regionsOnServer.add(hri);
+          }
+        }
+      }
+    }
+    return map;
+  }
+
   public synchronized ServerName getRegionServerOfRegion(HRegionInfo hri) {
     return regionAssignments.get(hri);
   }
@@ -375,23 +419,46 @@ public class RegionStates {
     ServerName oldServerName = regionAssignments.put(hri, serverName);
     if (!serverName.equals(oldServerName)) {
       LOG.info("Onlined " + hri.getShortNameToLog() + " on " + serverName);
-      Set<HRegionInfo> regions = serverHoldings.get(serverName);
-      if (regions == null) {
-        regions = new HashSet<HRegionInfo>();
-        serverHoldings.put(serverName, regions);
-      }
-      regions.add(hri);
+      addToServerHoldings(serverName, hri);
       if (oldServerName != null) {
         LOG.info("Offlined " + hri.getShortNameToLog() + " from " + oldServerName);
-        Set<HRegionInfo> oldRegions = serverHoldings.get(oldServerName);
-        oldRegions.remove(hri);
-        if (oldRegions.isEmpty()) {
-          serverHoldings.remove(oldServerName);
-        }
+        removeFromServerHoldings(oldServerName, hri);
       }
     }
   }
 
+  private void addToServerHoldings(ServerName serverName, HRegionInfo hri) {
+    Set<HRegionInfo> regions = serverHoldings.get(serverName);
+    if (regions == null) {
+      regions = new HashSet<HRegionInfo>();
+      serverHoldings.put(serverName, regions);
+    }
+    regions.add(hri);
+
+    HRegionInfo defaultReplica = RegionReplicaUtil.getRegionInfoForDefaultReplica(hri);
+    Set<HRegionInfo> replicas =
+        defaultReplicaToOtherReplicas.get(defaultReplica);
+    if (replicas == null) {
+      replicas = new HashSet<HRegionInfo>();
+      defaultReplicaToOtherReplicas.put(defaultReplica, replicas);
+    }
+    replicas.add(hri);
+  }
+
+  private void removeFromServerHoldings(ServerName serverName, HRegionInfo hri) {
+    Set<HRegionInfo> oldRegions = serverHoldings.get(serverName);
+    oldRegions.remove(hri);
+    if (oldRegions.isEmpty()) {
+      serverHoldings.remove(serverName);
+    }
+    HRegionInfo defaultReplica = RegionReplicaUtil.getRegionInfoForDefaultReplica(hri);
+    Set<HRegionInfo> replicas = defaultReplicaToOtherReplicas.get(defaultReplica);
+    replicas.remove(hri);
+    if (replicas.isEmpty()) {
+      defaultReplicaToOtherReplicas.remove(defaultReplica);
+    }
+  }
+
   /**
    * A dead server's hlogs have been split so that all the regions
    * used to be open on it can be safely assigned now. Mark them assignable.
@@ -459,11 +526,7 @@ public class RegionStates {
     ServerName oldServerName = regionAssignments.remove(hri);
     if (oldServerName != null) {
       LOG.info("Offlined " + hri.getShortNameToLog() + " from " + oldServerName);
-      Set<HRegionInfo> oldRegions = serverHoldings.get(oldServerName);
-      oldRegions.remove(hri);
-      if (oldRegions.isEmpty()) {
-        serverHoldings.remove(oldServerName);
-      }
+      removeFromServerHoldings(oldServerName, hri);
     }
   }
 

Modified: hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SnapshotOfRegionAssignmentFromMeta.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SnapshotOfRegionAssignmentFromMeta.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SnapshotOfRegionAssignmentFromMeta.java (original)
+++ hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SnapshotOfRegionAssignmentFromMeta.java Wed Feb 19 18:05:54 2014
@@ -33,6 +33,8 @@ import org.apache.commons.logging.LogFac
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.RegionLocations;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.catalog.CatalogTracker;
@@ -41,7 +43,6 @@ import org.apache.hadoop.hbase.catalog.M
 import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.master.balancer.FavoredNodeAssignmentHelper;
 import org.apache.hadoop.hbase.master.balancer.FavoredNodesPlan;
-import org.apache.hadoop.hbase.util.Pair;
 
 /**
  * Used internally for reading meta and constructing datastructures that are
@@ -100,20 +101,27 @@ public class SnapshotOfRegionAssignmentF
       public boolean visit(Result result) throws IOException {
         try {
           if (result ==  null || result.isEmpty()) return true;
-          Pair<HRegionInfo, ServerName> regionAndServer =
-              HRegionInfo.getHRegionInfoAndServerName(result);
-          HRegionInfo hri = regionAndServer.getFirst();
-          if (hri  == null) return true;
+          RegionLocations rl = MetaReader.getRegionLocations(result);
+          if (rl == null) return true;
+          HRegionInfo hri = rl.getRegionLocation(0).getRegionInfo();
+          if (hri == null) return true;
           if (hri.getTable() == null) return true;
           if (disabledTables.contains(hri.getTable())) {
             return true;
           }
           // Are we to include split parents in the list?
           if (excludeOfflinedSplitParents && hri.isSplit()) return true;
-          // Add the current assignment to the snapshot
-          addAssignment(hri, regionAndServer.getSecond());
-          addRegion(hri);
-          
+          HRegionLocation[] hrls = rl.getRegionLocations();
+
+          // Add the current assignment to the snapshot for all replicas
+          for (int i = 0; i < hrls.length; i++) {
+            if (hrls[i] == null) continue;
+            hri = hrls[i].getRegionInfo();
+            if (hri == null) continue;
+            addAssignment(hri, hrls[i].getServerName());
+            addRegion(hri);
+          }
+
           // the code below is to handle favored nodes
           byte[] favoredNodes = result.getValue(HConstants.CATALOG_FAMILY,
               FavoredNodeAssignmentHelper.FAVOREDNODES_QUALIFIER);
@@ -158,6 +166,8 @@ public class SnapshotOfRegionAssignmentF
     // Process the region to region server map
     regionToRegionServerMap.put(regionInfo, server);
 
+    if (server == null) return;
+
     // Process the region server to region map
     List<HRegionInfo> regionList = regionServerToRegionMap.get(server);
     if (regionList == null) {

Modified: hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ModifyRegionUtils.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ModifyRegionUtils.java?rev=1569861&r1=1569860&r2=1569861&view=diff
==============================================================================
--- hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ModifyRegionUtils.java (original)
+++ hbase/branches/hbase-10070/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ModifyRegionUtils.java Wed Feb 19 18:05:54 2014
@@ -27,7 +27,6 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.CompletionService;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorCompletionService;
-import java.util.concurrent.Future;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
@@ -39,6 +38,7 @@ import org.apache.hadoop.conf.Configurat
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.client.RegionReplicaUtil;
 import org.apache.hadoop.hbase.regionserver.HRegion;
 
 /**
@@ -111,7 +111,13 @@ public abstract class ModifyRegionUtils 
     CompletionService<HRegionInfo> completionService = new ExecutorCompletionService<HRegionInfo>(
         regionOpenAndInitThreadPool);
     List<HRegionInfo> regionInfos = new ArrayList<HRegionInfo>();
+    int defaultReplicas = 0;
     for (final HRegionInfo newRegion : newRegions) {
+      regionInfos.add(newRegion);
+      if (!RegionReplicaUtil.isDefaultReplica(newRegion)) {
+        continue;
+      }
+      defaultReplicas++;
       completionService.submit(new Callable<HRegionInfo>() {
         @Override
         public HRegionInfo call() throws IOException {
@@ -121,10 +127,8 @@ public abstract class ModifyRegionUtils 
     }
     try {
       // wait for all regions to finish creation
-      for (int i = 0; i < regionNumber; i++) {
-        Future<HRegionInfo> future = completionService.take();
-        HRegionInfo regionInfo = future.get();
-        regionInfos.add(regionInfo);
+      for (int i = 0; i < defaultReplicas; i++) {
+        completionService.take().get();
       }
     } catch (InterruptedException e) {
       LOG.error("Caught " + e + " during region creation");

Added: hbase/branches/hbase-10070/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterOperationsForRegionReplicas.java
URL: http://svn.apache.org/viewvc/hbase/branches/hbase-10070/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterOperationsForRegionReplicas.java?rev=1569861&view=auto
==============================================================================
--- hbase/branches/hbase-10070/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterOperationsForRegionReplicas.java (added)
+++ hbase/branches/hbase-10070/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterOperationsForRegionReplicas.java Wed Feb 19 18:05:54 2014
@@ -0,0 +1,328 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.MediumTests;
+import org.apache.hadoop.hbase.RegionLocations;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.catalog.CatalogTracker;
+import org.apache.hadoop.hbase.catalog.MetaReader;
+import org.apache.hadoop.hbase.catalog.MetaReader.Visitor;
+import org.apache.hadoop.hbase.client.Delete;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.RegionReplicaUtil;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.Pair;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(MediumTests.class)
+public class TestMasterOperationsForRegionReplicas {
+  final static Log LOG = LogFactory.getLog(TestRegionPlacement.class);
+  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+  private static HBaseAdmin admin;
+  private static int numSlaves = 2;
+
+  @BeforeClass
+  public static void setupBeforeClass() throws Exception {
+    Configuration conf = TEST_UTIL.getConfiguration();
+    conf.setBoolean("hbase.tests.use.shortcircuit.reads", false);
+    TEST_UTIL.startMiniCluster(numSlaves);
+    admin = new HBaseAdmin(conf);
+    while(admin.getClusterStatus().getServers().size() != numSlaves) {
+      Thread.sleep(100);
+    }
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TEST_UTIL.shutdownMiniCluster();
+  }
+
+  @Test
+  public void testCreateTableWithSingleReplica() throws Exception {
+    final int numRegions = 3;
+    final int numReplica = 1;
+    final TableName table = TableName.valueOf("singleReplicaTable");
+    try {
+      HTableDescriptor desc = new HTableDescriptor(table);
+      desc.setRegionReplication(numReplica);
+      desc.addFamily(new HColumnDescriptor("family"));
+      admin.createTable(desc, Bytes.toBytes("A"), Bytes.toBytes("Z"), numRegions);
+
+      CatalogTracker ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+      validateNumberOfRowsInMeta(table, numRegions, ct);
+      List<HRegionInfo> hris = MetaReader.getTableRegions(ct, table);
+      assert(hris.size() == numRegions * numReplica);
+    } finally {
+      admin.disableTable(table);
+      admin.deleteTable(table);
+    }
+  }
+
+  @Test
+  public void testCreateTableWithMultipleReplicas() throws Exception {
+    final TableName table = TableName.valueOf("fooTable");
+    final int numRegions = 3;
+    final int numReplica = 2;
+    try {
+      HTableDescriptor desc = new HTableDescriptor(table);
+      desc.setRegionReplication(numReplica);
+      desc.addFamily(new HColumnDescriptor("family"));
+      admin.createTable(desc, Bytes.toBytes("A"), Bytes.toBytes("Z"), numRegions);
+      TEST_UTIL.waitTableEnabled(table.getName());
+      CatalogTracker ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+      validateNumberOfRowsInMeta(table, numRegions, ct);
+
+      List<HRegionInfo> hris = MetaReader.getTableRegions(ct, table);
+      assert(hris.size() == numRegions * numReplica);
+      // check that the master created expected number of RegionState objects
+      for (int i = 0; i < numRegions; i++) {
+        for (int j = 0; j < numReplica; j++) {
+          HRegionInfo replica = RegionReplicaUtil.getRegionInfoForReplica(hris.get(i), j);
+          RegionState state = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager()
+              .getRegionStates().getRegionState(replica);
+          assert (state != null);
+        }
+      }
+      // TODO: HBASE-10351 should uncomment the following tests (since the tests assume region placements are handled)
+//      List<Result> metaRows = MetaReader.fullScan(ct);
+//      int numRows = 0;
+//      for (Result result : metaRows) {
+//        RegionLocations locations = MetaReader.getRegionLocations(result);
+//        HRegionInfo hri = locations.getRegionLocation().getRegionInfo();
+//        if (!hri.getTable().equals(table)) continue;
+//        numRows += 1;
+//        HRegionLocation[] servers = locations.getRegionLocations();
+//        // have two locations for the replicas of a region, and the locations should be different
+//        assert(servers.length == 2);
+//        assert(!servers[0].equals(servers[1]));
+//      }
+//      assert(numRows == numRegions);
+//
+//      // The same verification of the meta as above but with the SnapshotOfRegionAssignmentFromMeta
+//      // class
+//      validateFromSnapshotFromMeta(table, numRegions, numReplica, ct);
+//
+//      // Now kill the master, restart it and see if the assignments are kept
+//      ServerName master = TEST_UTIL.getHBaseClusterInterface().getClusterStatus().getMaster();
+//      TEST_UTIL.getHBaseClusterInterface().stopMaster(master);
+//      TEST_UTIL.getHBaseClusterInterface().waitForMasterToStop(master, 30000);
+//      TEST_UTIL.getHBaseClusterInterface().startMaster(master.getHostname());
+//      TEST_UTIL.getHBaseClusterInterface().waitForActiveAndReadyMaster();
+//      for (int i = 0; i < numRegions; i++) {
+//        for (int j = 0; j < numReplica; j++) {
+//          HRegionInfo replica = RegionReplicaUtil.getRegionInfoForReplica(hris.get(i), j);
+//          RegionState state = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager()
+//              .getRegionStates().getRegionState(replica);
+//          assert (state != null);
+//        }
+//      }
+//      validateFromSnapshotFromMeta(table, numRegions, numReplica, ct);
+//
+//      // Now shut the whole cluster down, and verify the assignments are kept so that the
+//      // availability constraints are met.
+//      TEST_UTIL.getConfiguration().setBoolean("hbase.master.startup.retainassign", true);
+//      TEST_UTIL.shutdownMiniHBaseCluster();
+//      TEST_UTIL.startMiniHBaseCluster(1, numSlaves);
+//      TEST_UTIL.waitTableEnabled(table.getName());
+//      ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+//      validateFromSnapshotFromMeta(table, numRegions, numReplica, ct);
+//
+//      // Now shut the whole cluster down, and verify regions are assigned even if there is only
+//      // one server running
+//      TEST_UTIL.shutdownMiniHBaseCluster();
+//      TEST_UTIL.startMiniHBaseCluster(1, 1);
+//      TEST_UTIL.waitTableEnabled(table.getName());
+//      ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+//      validateSingleRegionServerAssignment(ct, numRegions, numReplica);
+//      for (int i = 1; i < numSlaves; i++) { //restore the cluster
+//        TEST_UTIL.getMiniHBaseCluster().startRegionServer();
+//      }
+
+      //TODO: HBASE-10361 patch should uncomment the test below
+//      //check on alter table
+//      admin.disableTable(table);
+//      assert(admin.isTableDisabled(table));
+//      //increase the replica
+//      desc.setRegionReplication(numReplica + 1);
+//      admin.modifyTable(table, desc);
+//      admin.enableTable(table);
+//      assert(admin.isTableEnabled(table));
+//      List<HRegionInfo> regions = TEST_UTIL.getMiniHBaseCluster().getMaster()
+//          .getAssignmentManager().getRegionStates().getRegionsOfTable(table);
+//      assert(regions.size() == numRegions * (numReplica + 1));
+//
+//      //decrease the replica(earlier, table was modified to have a replica count of numReplica + 1)
+//      admin.disableTable(table);
+//      desc.setRegionReplication(numReplica);
+//      admin.modifyTable(table, desc);
+//      admin.enableTable(table);
+//      assert(admin.isTableEnabled(table));
+//      regions = TEST_UTIL.getMiniHBaseCluster().getMaster()
+//          .getAssignmentManager().getRegionStates().getRegionsOfTable(table);
+//      assert(regions.size() == numRegions * numReplica);
+//      //also make sure the meta table has the replica locations removed
+//      hris = MetaReader.getTableRegions(ct, table);
+//      assert(hris.size() == numRegions * numReplica);
+//      //just check that the number of default replica regions in the meta table are the same
+//      //as the number of regions the table was created with, and the count of the
+//      //replicas is numReplica for each region
+//      Map<HRegionInfo, Integer> defaultReplicas = new HashMap<HRegionInfo, Integer>();
+//      for (HRegionInfo hri : hris) {
+//        Integer i;
+//        HRegionInfo regionReplica0 = hri.getRegionInfoForReplica(0);
+//        defaultReplicas.put(regionReplica0, 
+//            (i = defaultReplicas.get(regionReplica0)) == null ? 1 : i + 1);
+//      }
+//      assert(defaultReplicas.size() == numRegions);
+//      Collection<Integer> counts = new HashSet<Integer>(defaultReplicas.values());
+//      assert(counts.size() == 1 && counts.contains(new Integer(numReplica)));
+    } finally {
+      admin.disableTable(table);
+      admin.deleteTable(table);
+    }
+  }
+
+  //@Test (TODO: enable when we have support for alter_table- HBASE-10361).
+  public void testIncompleteMetaTableReplicaInformation() throws Exception {
+    final TableName table = TableName.valueOf("fooTableTest1");
+    final int numRegions = 3;
+    final int numReplica = 2;
+    try {
+      // Create a table and let the meta table be updated with the location of the
+      // region locations.
+      HTableDescriptor desc = new HTableDescriptor(table);
+      desc.setRegionReplication(numReplica);
+      desc.addFamily(new HColumnDescriptor("family"));
+      admin.createTable(desc, Bytes.toBytes("A"), Bytes.toBytes("Z"), numRegions);
+      TEST_UTIL.waitTableEnabled(table.getName());
+      CatalogTracker ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+      Set<byte[]> tableRows = new HashSet<byte[]>();
+      List<HRegionInfo> hris = MetaReader.getTableRegions(ct, table);
+      for (HRegionInfo hri : hris) {
+        tableRows.add(hri.getRegionName());
+      }
+      admin.disableTable(table);
+      // now delete one replica info from all the rows
+      // this is to make the meta appear to be only partially updated
+      HTable metaTable = new HTable(TableName.META_TABLE_NAME, ct.getConnection());
+      for (byte[] row : tableRows) {
+        Delete deleteOneReplicaLocation = new Delete(row);
+        deleteOneReplicaLocation.deleteColumns(HConstants.CATALOG_FAMILY, MetaReader.getServerColumn(1));
+        deleteOneReplicaLocation.deleteColumns(HConstants.CATALOG_FAMILY, MetaReader.getSeqNumColumn(1));
+        deleteOneReplicaLocation.deleteColumns(HConstants.CATALOG_FAMILY, MetaReader.getStartCodeColumn(1));
+        metaTable.delete(deleteOneReplicaLocation);
+      }
+      metaTable.close();
+      // even if the meta table is partly updated, when we re-enable the table, we should
+      // get back the desired number of replicas for the regions
+      admin.enableTable(table);
+      assert(admin.isTableEnabled(table));
+      List<HRegionInfo> regions = TEST_UTIL.getMiniHBaseCluster().getMaster()
+          .getAssignmentManager().getRegionStates().getRegionsOfTable(table);
+      assert(regions.size() == numRegions * numReplica);
+    } finally {
+      admin.disableTable(table);
+      admin.deleteTable(table);
+    }
+  }
+
+  private String printRegions(List<HRegionInfo> regions) {
+    StringBuffer strBuf = new StringBuffer();
+    for (HRegionInfo r : regions) {
+      strBuf.append(" ____ " + r.toString());
+    }
+    return strBuf.toString();
+  }
+
+  private void validateNumberOfRowsInMeta(final TableName table, int numRegions, CatalogTracker ct)
+      throws IOException {
+    assert(admin.tableExists(table));
+    final AtomicInteger count = new AtomicInteger();
+    Visitor visitor = new Visitor() {
+      @Override
+      public boolean visit(Result r) throws IOException {
+        if (HRegionInfo.getHRegionInfo(r).getTable().equals(table)) count.incrementAndGet();
+        return true;
+      }
+    };
+    MetaReader.fullScan(ct, visitor);
+    assert(count.get() == numRegions);
+  }
+
+  private void validateFromSnapshotFromMeta(TableName table, int numRegions,
+      int numReplica, CatalogTracker ct) throws IOException {
+    SnapshotOfRegionAssignmentFromMeta snapshot = new SnapshotOfRegionAssignmentFromMeta(ct);
+    snapshot.initialize();
+    Map<HRegionInfo, ServerName> regionToServerMap = snapshot.getRegionToRegionServerMap();
+    assert(regionToServerMap.size() == numRegions * numReplica + 1); //'1' for the namespace
+    Map<ServerName, List<HRegionInfo>> serverToRegionMap = snapshot.getRegionServerToRegionMap();
+    for (Map.Entry<ServerName, List<HRegionInfo>> entry : serverToRegionMap.entrySet()) {
+      List<HRegionInfo> regions = entry.getValue();
+      Set<byte[]> setOfStartKeys = new HashSet<byte[]>();
+      for (HRegionInfo region : regions) {
+        byte[] startKey = region.getStartKey();
+        if (region.getTable().equals(table)) {
+          setOfStartKeys.add(startKey); //ignore other tables
+          LOG.info("--STARTKEY " + new String(startKey)+"--");
+        }
+      }
+      // the number of startkeys will be equal to the number of regions hosted in each server
+      // (each server will be hosting one replica of a region)
+      assertEquals(setOfStartKeys.size() , numRegions);
+    }
+  }
+
+  private void validateSingleRegionServerAssignment(CatalogTracker ct, int numRegions,
+      int numReplica) throws IOException {
+    SnapshotOfRegionAssignmentFromMeta snapshot = new SnapshotOfRegionAssignmentFromMeta(ct);
+    snapshot.initialize();
+    Map<HRegionInfo, ServerName>  regionToServerMap = snapshot.getRegionToRegionServerMap();
+    assert(regionToServerMap.size() == numRegions * numReplica + 1); //'1' for the namespace
+    Map<ServerName, List<HRegionInfo>> serverToRegionMap = snapshot.getRegionServerToRegionMap();
+    assert(serverToRegionMap.keySet().size() == 1);
+    assert(serverToRegionMap.values().iterator().next().size() == numRegions * numReplica + 1);
+  }
+}