You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by to...@apache.org on 2020/08/10 04:21:44 UTC

[hbase] 01/04: Some extra fixes as precaution

This is an automated email from the ASF dual-hosted git repository.

toffer pushed a commit to branch HBASE-11288.branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git

commit 87e2bb70b680f13e2eddb402f3ed98eeef2cfcb5
Author: Francis Liu <to...@apache.org>
AuthorDate: Fri Aug 7 02:09:51 2020 -0700

    Some extra fixes as precaution
---
 .../org/apache/hadoop/hbase/HTableDescriptor.java  |  6 +++-
 .../hadoop/hbase/client/AsyncClientScanner.java    |  4 +--
 .../hbase/client/ConnectionImplementation.java     |  8 ++++-
 .../org/apache/hadoop/hbase/client/HBaseAdmin.java |  4 ++-
 .../apache/hadoop/hbase/client/MasterCallable.java |  8 +++++
 .../hadoop/hbase/client/RawAsyncHBaseAdmin.java    |  8 ++---
 .../hadoop/hbase/client/TableDescriptor.java       | 14 +++++++++
 .../hbase/client/TableDescriptorBuilder.java       | 21 +++++++++++++
 .../hbase/snapshot/TestSecureExportSnapshot.java   |  2 +-
 .../hadoop/hbase/master/RegionsRecoveryChore.java  |  2 +-
 .../hadoop/hbase/master/SplitWALManager.java       |  2 +-
 .../hadoop/hbase/master/TableStateManager.java     |  2 +-
 .../hbase/master/assignment/AssignmentManager.java |  9 ++++++
 .../hbase/master/balancer/SimpleLoadBalancer.java  |  2 +-
 .../master/procedure/MasterProcedureUtil.java      |  4 ++-
 .../master/procedure/ServerCrashProcedure.java     |  6 +++-
 .../apache/hadoop/hbase/regionserver/HRegion.java  | 12 +++++---
 .../hadoop/hbase/regionserver/HRegionServer.java   | 34 +++++++++++++---------
 .../apache/hadoop/hbase/regionserver/HStore.java   |  2 +-
 .../hadoop/hbase/regionserver/MemStoreFlusher.java |  3 +-
 .../hadoop/hbase/regionserver/RSRpcServices.java   |  8 ++---
 .../hbase/regionserver/RegionSplitPolicy.java      |  4 ++-
 .../regionserver/StorefileRefresherChore.java      |  3 +-
 .../wal/BoundedRecoveredHFilesOutputSink.java      |  2 +-
 24 files changed, 128 insertions(+), 42 deletions(-)

diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
index 77d2b47..3f30af3 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
@@ -131,7 +131,11 @@ public class HTableDescriptor implements TableDescriptor, Comparable<HTableDescr
    * @return always return the false
    */
   public boolean isRootRegion() {
-    return false;
+    return delegatee.isRootRegion();
+  }
+
+  public boolean isRootTable() {
+    return delegatee.isRootTable();
   }
 
   /**
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncClientScanner.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncClientScanner.java
index 5fd00a5..8664d56 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncClientScanner.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncClientScanner.java
@@ -195,8 +195,8 @@ class AsyncClientScanner {
   }
 
   private long getPrimaryTimeoutNs() {
-    return TableName.isMetaTableName(tableName) ? conn.connConf.getPrimaryMetaScanTimeoutNs()
-      : conn.connConf.getPrimaryScanTimeoutNs();
+    return TableName.isRootTableName(tableName) || TableName.isMetaTableName(tableName) ?
+      conn.connConf.getPrimaryMetaScanTimeoutNs() : conn.connConf.getPrimaryScanTimeoutNs();
   }
 
   private void openScanner() {
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java
index 21cedfe..0a525c9 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java
@@ -661,6 +661,10 @@ class ConnectionImplementation implements ClusterConnection, Closeable {
         LOG.debug("Table {} not enabled", tableName);
         return false;
       }
+      if (TableName.isRootTableName(tableName)) {
+        // meta table is always available
+        return true;
+      }
       if (TableName.isMetaTableName(tableName)) {
         // meta table is always available
         return true;
@@ -735,7 +739,9 @@ class ConnectionImplementation implements ClusterConnection, Closeable {
   public List<HRegionLocation> locateRegions(TableName tableName, boolean useCache,
       boolean offlined) throws IOException {
     List<RegionInfo> regions;
-    if (TableName.isMetaTableName(tableName)) {
+    if (TableName.isRootTableName(tableName)) {
+      regions = Collections.singletonList(RegionInfoBuilder.ROOT_REGIONINFO);
+    } else  if (TableName.isMetaTableName(tableName)) {
       regions = Collections.singletonList(RegionInfoBuilder.FIRST_META_REGIONINFO);
     } else {
       regions = MetaTableAccessor.getTableRegions(this, tableName, !offlined);
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
index 4b1a738..c06d275 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
@@ -424,7 +424,9 @@ public class HBaseAdmin implements Admin {
 
   @Override
   public List<RegionInfo> getRegions(TableName tableName) throws IOException {
-    if (TableName.isMetaTableName(tableName)) {
+    if (TableName.isRootTableName(tableName)) {
+      return Arrays.asList(RegionInfoBuilder.ROOT_REGIONINFO);
+    } else if (TableName.isMetaTableName(tableName)) {
       return Arrays.asList(RegionInfoBuilder.FIRST_META_REGIONINFO);
     } else {
       return MetaTableAccessor.getTableRegions(connection, tableName, true);
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MasterCallable.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MasterCallable.java
index 7ae9731..1089573 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MasterCallable.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MasterCallable.java
@@ -132,11 +132,19 @@ abstract class MasterCallable<V> implements RetryingCallable<V>, Closeable {
    * @param regionName RegionName. If hbase:meta, we'll set high priority.
    */
   void setPriority(final byte[] regionName) {
+    if (isRootRegion(regionName)) {
+      setPriority(TableName.ROOT_TABLE_NAME);
+    }
     if (isMetaRegion(regionName)) {
       setPriority(TableName.META_TABLE_NAME);
     }
   }
 
+  private static boolean isRootRegion(final byte[] regionName) {
+    return Bytes.equals(regionName, RegionInfoBuilder.ROOT_REGIONINFO.getRegionName()) ||
+      Bytes.equals(regionName, RegionInfoBuilder.ROOT_REGIONINFO.getEncodedNameAsBytes());
+  }
+
   private static boolean isMetaRegion(final byte[] regionName) {
     return Bytes.equals(regionName, RegionInfoBuilder.FIRST_META_REGIONINFO.getRegionName()) ||
       Bytes.equals(regionName, RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedNameAsBytes());
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
index 1091ef6..cba6b18 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
@@ -480,7 +480,7 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
 
   @Override
   public CompletableFuture<Boolean> tableExists(TableName tableName) {
-    if (TableName.isMetaTableName(tableName)) {
+    if (TableName.isRootTableName(tableName) || TableName.isMetaTableName(tableName)) {
       return CompletableFuture.completedFuture(true);
     }
     return AsyncMetaTableAccessor.tableExists(metaTable, tableName);
@@ -692,7 +692,7 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
 
   @Override
   public CompletableFuture<Boolean> isTableEnabled(TableName tableName) {
-    if (TableName.isMetaTableName(tableName)) {
+    if (TableName.isRootTableName(tableName) || TableName.isMetaTableName(tableName)) {
       return CompletableFuture.completedFuture(true);
     }
     CompletableFuture<Boolean> future = new CompletableFuture<>();
@@ -705,7 +705,7 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
 
   @Override
   public CompletableFuture<Boolean> isTableDisabled(TableName tableName) {
-    if (TableName.isMetaTableName(tableName)) {
+    if (TableName.isRootTableName(tableName) || TableName.isMetaTableName(tableName)) {
       return CompletableFuture.completedFuture(false);
     }
     CompletableFuture<Boolean> future = new CompletableFuture<>();
@@ -730,7 +730,7 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
 
   private CompletableFuture<Boolean> isTableAvailable(TableName tableName,
       Optional<byte[][]> splitKeys) {
-    if (TableName.isMetaTableName(tableName)) {
+    if (TableName.isRootTableName(tableName) || TableName.isMetaTableName(tableName)) {
       return connection.registry.getMetaRegionLocations().thenApply(locs -> Stream
         .of(locs.getRegionLocations()).allMatch(loc -> loc != null && loc.getServerName() != null));
     }
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java
index 2ae273d..a97b394 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java
@@ -278,6 +278,20 @@ public interface TableDescriptor {
    *
    * @return true if this table is <code> hbase:meta </code> region
    */
+  boolean isRootRegion();
+
+  /**
+   * Checks if the table is a <code>hbase:meta</code> table
+   *
+   * @return true if table is <code> hbase:meta </code> region.
+   */
+  boolean isRootTable();
+
+  /**
+   * Checks if this table is <code> hbase:meta </code> region.
+   *
+   * @return true if this table is <code> hbase:meta </code> region
+   */
   boolean isMetaRegion();
 
   /**
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java
index d35dd2c..b98c02a 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java
@@ -642,6 +642,27 @@ public class TableDescriptorBuilder {
      * @return true if this table is <code> hbase:meta </code> region
      */
     @Override
+    public boolean isRootRegion() {
+      //TODO should we add a IS_ROOT key or rename/keep IS_META to mean IS_CATALOG
+      return getTableName().equals(TableName.ROOT_TABLE_NAME);
+    }
+
+    /**
+     * Checks if the table is a <code>hbase:meta</code> table
+     *
+     * @return true if table is <code> hbase:meta </code> region.
+     */
+    @Override
+    public boolean isRootTable() {
+      return isRootRegion();
+    }
+
+    /**
+     * Checks if this table is <code> hbase:meta </code> region.
+     *
+     * @return true if this table is <code> hbase:meta </code> region
+     */
+    @Override
     public boolean isMetaRegion() {
       return getOrDefault(IS_META_KEY, Boolean::valueOf, false);
     }
diff --git a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestSecureExportSnapshot.java b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestSecureExportSnapshot.java
index 133934d..4bb45a0 100644
--- a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestSecureExportSnapshot.java
+++ b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestSecureExportSnapshot.java
@@ -32,7 +32,7 @@ import org.junit.experimental.categories.Category;
 /**
  * Reruns TestExportSnapshot using ExportSnapshot in secure mode.
  */
-@Ignore
+//@Ignore
 @Category({VerySlowRegionServerTests.class, LargeTests.class})
 public class TestSecureExportSnapshot extends TestExportSnapshot {
 
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionsRecoveryChore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionsRecoveryChore.java
index 0ee5a1b..e6baecd 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionsRecoveryChore.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionsRecoveryChore.java
@@ -155,7 +155,7 @@ public class RegionsRecoveryChore extends ScheduledChore {
 
     final RegionInfo regionInfo = hMaster.getAssignmentManager().getRegionInfo(regionName);
     final TableName tableName = regionInfo.getTable();
-    if (TableName.isMetaTableName(tableName)) {
+    if (TableName.isRootTableName(tableName) || TableName.isMetaTableName(tableName)) {
       // Do not reopen regions of meta table even if it has
       // high store file reference count
       return;
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SplitWALManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SplitWALManager.java
index 5ef25a1..fbd0fed 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SplitWALManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SplitWALManager.java
@@ -115,7 +115,7 @@ public class SplitWALManager {
     return splitWALs(crashedServer, SplitType.USER);
   }
 
-  public List<Procedure> splitWALs(ServerName crashedServer, SplitType splitType)
+  public List<Procedure>  splitWALs(ServerName crashedServer, SplitType splitType)
       throws IOException {
     try {
       // 1. list all splitting files
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableStateManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableStateManager.java
index 4360e74..1e7f1a9 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableStateManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableStateManager.java
@@ -221,7 +221,7 @@ public class TableStateManager {
     });
     for (TableDescriptor tableDesc : tableDescriptors.getAll().values()) {
       TableName tableName = tableDesc.getTableName();
-      if (TableName.isMetaTableName(tableName)) {
+      if (TableName.isRootTableName(tableName) || TableName.isMetaTableName(tableName)) {
         // This table is always enabled. No fixup needed. No entry in hbase:meta needed.
         // Call through to fixTableState though in case a super class wants to do something.
         fixTableState(new TableState(tableName, TableState.State.ENABLED));
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java
index 2881f83..79d7b64 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java
@@ -918,6 +918,15 @@ public class AssignmentManager {
 
   @VisibleForTesting
   static int compare(TransitRegionStateProcedure left, TransitRegionStateProcedure right) {
+    //TODO this is broken once we have more meta entries
+    if (left.getRegion().isRootRegion()) {
+      if (right.getRegion().isRootRegion()) {
+        return RegionInfo.COMPARATOR.compare(left.getRegion(), right.getRegion());
+      }
+      return -1;
+    } else if (right.getRegion().isRootRegion()) {
+      return +1;
+    }
     if (left.getRegion().isMetaRegion()) {
       if (right.getRegion().isMetaRegion()) {
         return RegionInfo.COMPARATOR.compare(left.getRegion(), right.getRegion());
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java
index d8b4256..9c58207 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java
@@ -396,7 +396,7 @@ public class SimpleLoadBalancer extends BaseLoadBalancer {
           balanceInfo == null ? 0 : balanceInfo.getNextRegionForUnload();
         if (idx >= server.getValue().size()) break;
         RegionInfo region = server.getValue().get(idx);
-        if (region.isMetaRegion()) continue; // Don't move meta regions.
+        if (region.isRootRegion() || region.isMetaRegion()) continue; // Don't move meta regions.
         regionsToMove.add(new RegionPlan(region, server.getKey().getServerName(), null));
         balanceInfo.setNumRegionsAdded(balanceInfo.getNumRegionsAdded() - 1);
         balanceInfo.setNextRegionForUnload(balanceInfo.getNextRegionForUnload() + 1);
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/MasterProcedureUtil.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/MasterProcedureUtil.java
index efe3d83..2f68f21 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/MasterProcedureUtil.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/MasterProcedureUtil.java
@@ -166,7 +166,9 @@ public final class MasterProcedureUtil {
    * user tables are 1.
    */
   public static int getTablePriority(TableName tableName) {
-    if (TableName.isMetaTableName(tableName)) {
+    if (TableName.isRootTableName(tableName)) {
+      return 4;
+    } else if (TableName.isMetaTableName(tableName)) {
       return 3;
     } else if (tableName.isSystemTable()) {
       return 2;
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ServerCrashProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ServerCrashProcedure.java
index 9ced487..5393fd0 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ServerCrashProcedure.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ServerCrashProcedure.java
@@ -350,10 +350,14 @@ public class ServerCrashProcedure
     if (regionsOnCrashedServer == null) {
       return false;
     }
-    regionsOnCrashedServer.removeIf(this::isDefaultMetaRegion);
+    regionsOnCrashedServer.removeIf((x) -> isDefaultMetaRegion(x) || isDefaultRootRegion(x));
     return !regionsOnCrashedServer.isEmpty();
   }
 
+  private boolean isDefaultRootRegion(RegionInfo hri) {
+    return hri.isRootRegion() && RegionReplicaUtil.isDefaultReplica(hri);
+  }
+
   private boolean isDefaultMetaRegion(RegionInfo hri) {
     return hri.isMetaRegion() && RegionReplicaUtil.isDefaultReplica(hri);
   }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
index fef1fa5..87d9c09 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
@@ -778,7 +778,8 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
     this.cellComparator = htd.isMetaTable() ||
       conf.getBoolean(USE_META_CELL_COMPARATOR, DEFAULT_USE_META_CELL_COMPARATOR) ?
         CellComparatorImpl.META_COMPARATOR :
-        CellComparatorImpl.COMPARATOR;
+          htd.isRootTable() ? CellComparatorImpl.ROOT_COMPARATOR : CellComparatorImpl.COMPARATOR;
+
     this.lock = new ReentrantReadWriteLock(conf.getBoolean(FAIR_REENTRANT_CLOSE_LOCK,
         DEFAULT_FAIR_REENTRANT_CLOSE_LOCK));
     this.flushCheckInterval = conf.getInt(MEMSTORE_PERIODIC_FLUSH_INTERVAL,
@@ -4542,7 +4543,7 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
   */
   void checkResources() throws RegionTooBusyException {
     // If catalog region, do not impose resource constraints or block updates.
-    if (this.getRegionInfo().isMetaRegion()) return;
+    if (this.getRegionInfo().isRootRegion() || this.getRegionInfo().isMetaRegion()) return;
 
     MemStoreSize mss = this.memStoreSizing.getMemStoreSize();
     if (mss.getHeapSize() + mss.getOffHeapSize() > this.blockingMemStoreSize) {
@@ -8514,7 +8515,9 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
    */
   public Optional<byte[]> checkSplit(boolean force) {
     // Can't split META
-    if (this.getRegionInfo().isMetaRegion() ||
+    if (
+      this.getRegionInfo().isRootRegion() ||
+      this.getRegionInfo().isMetaRegion() ||
       TableName.NAMESPACE_TABLE_NAME.equals(this.getRegionInfo().getTable())) {
       return Optional.empty();
     }
@@ -8717,7 +8720,7 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
    * @throws IOException If anything goes wrong with DFS
    */
   private void sync(long txid, Durability durability) throws IOException {
-    if (this.getRegionInfo().isMetaRegion()) {
+    if (this.getRegionInfo().isRootRegion() || this.getRegionInfo().isMetaRegion()) {
       this.wal.sync(txid);
     } else {
       switch(durability) {
@@ -8881,6 +8884,7 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
     StringBuilder buf = new StringBuilder();
     buf.append(title + ", ");
     buf.append(getRegionInfo().toString());
+    buf.append(getRegionInfo().isRootRegion() ? " root region " : " ");
     buf.append(getRegionInfo().isMetaRegion() ? " meta region " : " ");
     buf.append("stores: ");
     for (HStore s : stores.values()) {
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
index 00ba4c0..64deba5 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
@@ -119,7 +119,6 @@ import org.apache.hadoop.hbase.ipc.ServerRpcController;
 import org.apache.hadoop.hbase.log.HBaseMarkers;
 import org.apache.hadoop.hbase.master.HMaster;
 import org.apache.hadoop.hbase.master.LoadBalancer;
-import org.apache.hadoop.hbase.master.RegionState.State;
 import org.apache.hadoop.hbase.master.RegionState;
 import org.apache.hadoop.hbase.mob.MobFileCache;
 import org.apache.hadoop.hbase.procedure.RegionServerProcedureManagerHost;
@@ -136,6 +135,7 @@ import org.apache.hadoop.hbase.regionserver.compactions.CompactionProgress;
 import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequester;
 import org.apache.hadoop.hbase.regionserver.handler.CloseMetaHandler;
 import org.apache.hadoop.hbase.regionserver.handler.CloseRegionHandler;
+import org.apache.hadoop.hbase.regionserver.handler.CloseRootHandler;
 import org.apache.hadoop.hbase.regionserver.handler.RSProcedureHandler;
 import org.apache.hadoop.hbase.regionserver.handler.RegionReplicaFlushHandler;
 import org.apache.hadoop.hbase.namequeues.NamedQueueRecorder;
@@ -160,7 +160,6 @@ import org.apache.hadoop.hbase.util.CompressionTest;
 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
 import org.apache.hadoop.hbase.util.FSTableDescriptors;
 import org.apache.hadoop.hbase.util.FSUtils;
-import org.apache.hadoop.hbase.util.FutureUtils;
 import org.apache.hadoop.hbase.util.JvmPauseMonitor;
 import org.apache.hadoop.hbase.util.NettyEventLoopGroupConfig;
 import org.apache.hadoop.hbase.util.Pair;
@@ -1118,13 +1117,13 @@ public class HRegionServer extends Thread implements
     }
 
     // Closing the compactSplit thread before closing meta regions
-    if (!this.killed && containsMetaTableRegions()) {
+    if (!this.killed && containsCatalogTableRegions()) {
       if (!abortRequested.get() || this.dataFsOk) {
         if (this.compactSplitThread != null) {
           this.compactSplitThread.join();
           this.compactSplitThread = null;
         }
-        closeMetaTableRegions(abortRequested.get());
+        closeCatalogTableRegions(abortRequested.get());
       }
     }
 
@@ -1190,16 +1189,17 @@ public class HRegionServer extends Thread implements
     LOG.info("Exiting; stopping=" + this.serverName + "; zookeeper connection closed.");
   }
 
-  //TODO francis update this
-  private boolean containsMetaTableRegions() {
-    return onlineRegions.containsKey(RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedName());
+  private boolean containsCatalogTableRegions() {
+    return onlineRegions.containsKey(RegionInfoBuilder.ROOT_REGIONINFO.getEncodedName()) ||
+      onlineRegions.containsKey(RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedName());
   }
 
   private boolean areAllUserRegionsOffline() {
     if (getNumberOfOnlineRegions() > 2) return false;
     boolean allUserRegionsOffline = true;
     for (Map.Entry<String, HRegion> e: this.onlineRegions.entrySet()) {
-      if (!e.getValue().getRegionInfo().isMetaRegion()) {
+      if (!e.getValue().getRegionInfo().isRootRegion() ||
+        !e.getValue().getRegionInfo().isMetaRegion()) {
         allUserRegionsOffline = false;
         break;
       }
@@ -2328,7 +2328,7 @@ public class HRegionServer extends Thread implements
 
     if (code == TransitionCode.OPENED) {
       Preconditions.checkArgument(hris != null && hris.length == 1);
-      if (hris[0].isMetaRegion()) {
+      if (hris[0].isRootRegion()) {
         try {
           MetaTableLocator.setMetaLocation(getZooKeeper(), serverName,
               hris[0].getReplicaId(), RegionState.State.OPEN);
@@ -2821,20 +2821,25 @@ public class HRegionServer extends Thread implements
    * Close meta region if we carry it
    * @param abort Whether we're running an abort.
    */
-  private void closeMetaTableRegions(final boolean abort) {
+  private void closeCatalogTableRegions(final boolean abort) {
+    HRegion root = null;
     HRegion meta = null;
     this.onlineRegionsLock.writeLock().lock();
     try {
       for (Map.Entry<String, HRegion> e: onlineRegions.entrySet()) {
         RegionInfo hri = e.getValue().getRegionInfo();
+        if (hri.isRootRegion()) {
+          root = e.getValue();
+        }
         if (hri.isMetaRegion()) {
           meta = e.getValue();
         }
-        if (meta != null) break;
+        if (root != null && meta != null) break;
       }
     } finally {
       this.onlineRegionsLock.writeLock().unlock();
     }
+    if (root != null) closeRegionIgnoreErrors(root.getRegionInfo(), abort);
     if (meta != null) closeRegionIgnoreErrors(meta.getRegionInfo(), abort);
   }
 
@@ -2849,7 +2854,8 @@ public class HRegionServer extends Thread implements
     try {
       for (Map.Entry<String, HRegion> e: this.onlineRegions.entrySet()) {
         HRegion r = e.getValue();
-        if (!r.getRegionInfo().isMetaRegion() && r.isAvailable()) {
+        if (!r.getRegionInfo().isRootRegion() && !r.getRegionInfo().isMetaRegion()
+          && r.isAvailable()) {
           // Don't update zk with this close transition; pass false.
           closeRegionIgnoreErrors(r.getRegionInfo(), abort);
         }
@@ -3294,7 +3300,9 @@ public class HRegionServer extends Thread implements
 
     CloseRegionHandler crh;
     final RegionInfo hri = actualRegion.getRegionInfo();
-    if (hri.isMetaRegion()) {
+    if (hri.isRootRegion()) {
+      crh = new CloseRootHandler(this, this, hri, abort);
+    } else if (hri.isMetaRegion()) {
       crh = new CloseMetaHandler(this, this, hri, abort);
     } else {
       crh = new CloseRegionHandler(this, this, hri, abort, destination);
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java
index 4e3c5ba..bb893fd 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java
@@ -2130,7 +2130,7 @@ public class HStore implements Store, HeapSize, StoreConfigInformation,
     this.lock.readLock().lock();
     try {
       // Should already be enforced by the split policy!
-      assert !this.getRegionInfo().isMetaRegion();
+      assert !this.getRegionInfo().isRootRegion() && !this.getRegionInfo().isMetaRegion();
       // Not split-able if we find a reference store file present in the store.
       if (hasReferences()) {
         LOG.trace("Not splittable; has references: {}", this);
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreFlusher.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreFlusher.java
index 1537f7c..f2a1779 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreFlusher.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreFlusher.java
@@ -548,7 +548,8 @@ class MemStoreFlusher implements FlushRequester {
    */
   private boolean flushRegion(final FlushRegionEntry fqe) {
     HRegion region = fqe.region;
-    if (!region.getRegionInfo().isMetaRegion() && isTooManyStoreFiles(region)) {
+    if (!region.getRegionInfo().isRootRegion() && !region.getRegionInfo().isMetaRegion()
+      && isTooManyStoreFiles(region)) {
       if (fqe.isMaximumWait(this.blockingWaitTime)) {
         LOG.info("Waited " + (EnvironmentEdgeManager.currentTime() - fqe.createTime) +
           "ms on a compaction to clean up 'too many store files'; waited " +
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
index f15c662..9c3349f 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
@@ -641,7 +641,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
     throws IOException {
     int countOfCompleteMutation = 0;
     try {
-      if (!region.getRegionInfo().isMetaRegion()) {
+      if (!region.getRegionInfo().isRootRegion() && !region.getRegionInfo().isMetaRegion()) {
         regionServer.getMemStoreFlusher().reclaimMemStoreMemory();
       }
       RowMutations rm = null;
@@ -1080,7 +1080,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
         quota.addMutation(mutation);
       }
 
-      if (!region.getRegionInfo().isMetaRegion()) {
+      if (!region.getRegionInfo().isRootRegion() && !region.getRegionInfo().isMetaRegion()) {
         regionServer.getMemStoreFlusher().reclaimMemStoreMemory();
       }
 
@@ -1211,7 +1211,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
         }
       }
       requestCount.increment();
-      if (!region.getRegionInfo().isMetaRegion()) {
+      if (!region.getRegionInfo().isRootRegion() && !region.getRegionInfo().isMetaRegion()) {
         regionServer.getMemStoreFlusher().reclaimMemStoreMemory();
       }
       return region.batchReplay(mutations.toArray(
@@ -3059,7 +3059,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
       region = getRegion(request.getRegion());
       MutateResponse.Builder builder = MutateResponse.newBuilder();
       MutationProto mutation = request.getMutation();
-      if (!region.getRegionInfo().isMetaRegion()) {
+      if (!region.getRegionInfo().isRootRegion() && !region.getRegionInfo().isMetaRegion()) {
         regionServer.getMemStoreFlusher().reclaimMemStoreMemory();
       }
       long nonceGroup = request.hasNonceGroup() ? request.getNonceGroup() : HConstants.NO_NONCE;
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionSplitPolicy.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionSplitPolicy.java
index 3079925..8165f88 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionSplitPolicy.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionSplitPolicy.java
@@ -75,7 +75,9 @@ public abstract class RegionSplitPolicy extends Configured {
    * @return {@code true} if the specified region can be split.
    */
   protected boolean canSplit() {
-    return !region.getRegionInfo().isMetaRegion() && region.isAvailable() &&
+    return !region.getRegionInfo().isRootRegion() &&
+      !region.getRegionInfo().isMetaRegion() &&
+      region.isAvailable() &&
       !TableName.NAMESPACE_TABLE_NAME.equals(region.getRegionInfo().getTable()) &&
       region.getStores().stream().allMatch(HStore::canSplit);
   }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StorefileRefresherChore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StorefileRefresherChore.java
index 18f7e18..394d86a 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StorefileRefresherChore.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StorefileRefresherChore.java
@@ -91,7 +91,8 @@ public class StorefileRefresherChore extends ScheduledChore {
       }
       // don't refresh unless enabled for all files, or it the meta region
       // meta region don't have WAL replication for replicas enabled yet
-      if (onlyMetaRefresh && !r.getRegionInfo().isMetaRegion()) continue;
+      if (onlyMetaRefresh &&
+        !r.getRegionInfo().isRootRegion() && !r.getRegionInfo().isMetaRegion()) continue;
       String encodedName = r.getRegionInfo().getEncodedName();
       long time = EnvironmentEdgeManager.currentTime();
       if (!lastRefreshTimes.containsKey(encodedName)) {
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/BoundedRecoveredHFilesOutputSink.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/BoundedRecoveredHFilesOutputSink.java
index d1be4fb..ad7387e 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/BoundedRecoveredHFilesOutputSink.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/BoundedRecoveredHFilesOutputSink.java
@@ -203,7 +203,7 @@ public class BoundedRecoveredHFilesOutputSink extends OutputSink {
     HFileContext hFileContext = new HFileContextBuilder().
       withChecksumType(HStore.getChecksumType(walSplitter.conf)).
       withBytesPerCheckSum(HStore.getBytesPerChecksum(walSplitter.conf)).
-      withCellComparator(isMetaTable?
+      withCellComparator(isRootTable? CellComparatorImpl.ROOT_COMPARATOR : isMetaTable?
         CellComparatorImpl.META_COMPARATOR: CellComparatorImpl.COMPARATOR).build();
     return writerBuilder.withFileContext(hFileContext).build();
   }