You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by zh...@apache.org on 2022/06/13 03:09:14 UTC

[hbase] branch master updated: HBASE-27028 Add a shell command for flushing master local region (#4457)

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

zhangduo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/master by this push:
     new 002c92cd7aa HBASE-27028 Add a shell command for flushing master local region (#4457)
002c92cd7aa is described below

commit 002c92cd7aa84ec04c80978efc775b869d14c2e2
Author: LiangJun He <20...@163.com>
AuthorDate: Mon Jun 13 11:09:05 2022 +0800

    HBASE-27028 Add a shell command for flushing master local region (#4457)
    
    Signed-off-by: Duo Zhang <zh...@apache.org>
---
 .../java/org/apache/hadoop/hbase/client/Admin.java |  5 +++
 .../hadoop/hbase/client/AdminOverAsyncAdmin.java   |  5 +++
 .../org/apache/hadoop/hbase/client/AsyncAdmin.java |  5 +++
 .../hadoop/hbase/client/AsyncHBaseAdmin.java       |  5 +++
 .../hadoop/hbase/client/RawAsyncHBaseAdmin.java    | 12 +++++++
 .../src/main/protobuf/server/master/Master.proto   |  6 ++++
 .../hadoop/hbase/coprocessor/MasterObserver.java   | 16 ++++++++++
 .../org/apache/hadoop/hbase/master/HMaster.java    | 20 ++++++++++++
 .../hadoop/hbase/master/MasterCoprocessorHost.java | 18 +++++++++++
 .../hadoop/hbase/master/MasterRpcServices.java     | 14 ++++++++
 .../apache/hadoop/hbase/master/MasterServices.java |  5 +++
 .../hadoop/hbase/master/region/MasterRegion.java   |  7 ++--
 .../region/MasterRegionFlusherAndCompactor.java    | 14 ++++++--
 .../hbase/coprocessor/TestMasterObserver.java      | 35 ++++++++++++++++++++
 .../hbase/master/MockNoopMasterServices.java       |  4 +++
 .../hbase/master/region/TestMasterRegionFlush.java |  1 -
 .../hbase/rsgroup/VerifyingRSGroupAdmin.java       |  5 +++
 hbase-shell/src/main/ruby/hbase/admin.rb           |  8 ++++-
 hbase-shell/src/main/ruby/shell.rb                 |  1 +
 .../main/ruby/shell/commands/flush_master_store.rb | 37 ++++++++++++++++++++++
 .../hadoop/hbase/thrift2/client/ThriftAdmin.java   |  5 +++
 21 files changed, 220 insertions(+), 8 deletions(-)

diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
index 736daf93eff..d2b57476128 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
@@ -2539,4 +2539,9 @@ public interface Admin extends Abortable, Closeable {
    */
   List<LogEntry> getLogEntries(Set<ServerName> serverNames, String logType, ServerType serverType,
     int limit, Map<String, Object> filterParams) throws IOException;
+
+  /**
+   * Flush master local region
+   */
+  void flushMasterStore() throws IOException;
 }
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AdminOverAsyncAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AdminOverAsyncAdmin.java
index 901c86ff374..efab2490462 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AdminOverAsyncAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AdminOverAsyncAdmin.java
@@ -1078,4 +1078,9 @@ class AdminOverAsyncAdmin implements Admin {
     ServerType serverType, int limit, Map<String, Object> filterParams) throws IOException {
     return get(admin.getLogEntries(serverNames, logType, serverType, limit, filterParams));
   }
+
+  @Override
+  public void flushMasterStore() throws IOException {
+    get(admin.flushMasterStore());
+  }
 }
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
index 47b89c96a4b..e0a254bb2aa 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
@@ -1785,4 +1785,9 @@ public interface AsyncAdmin {
    */
   CompletableFuture<List<LogEntry>> getLogEntries(Set<ServerName> serverNames, String logType,
     ServerType serverType, int limit, Map<String, Object> filterParams);
+
+  /**
+   * Flush master local region
+   */
+  CompletableFuture<Void> flushMasterStore();
 }
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
index 7b44c2d341d..ba016111cd3 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
@@ -949,4 +949,9 @@ class AsyncHBaseAdmin implements AsyncAdmin {
     String logType, ServerType serverType, int limit, Map<String, Object> filterParams) {
     return wrap(rawAdmin.getLogEntries(serverNames, logType, serverType, limit, filterParams));
   }
+
+  @Override
+  public CompletableFuture<Void> flushMasterStore() {
+    return wrap(rawAdmin.flushMasterStore());
+  }
 }
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 d88279eeafc..3ec2c741293 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
@@ -178,6 +178,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.EnableTabl
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.EnableTableResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ExecProcedureRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ExecProcedureResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.FlushMasterStoreRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.FlushMasterStoreResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetClusterStatusRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetClusterStatusResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetCompletedSnapshotsRequest;
@@ -4280,4 +4282,14 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
         return CompletableFuture.completedFuture(Collections.emptyList());
     }
   }
+
+  @Override
+  public CompletableFuture<Void> flushMasterStore() {
+    FlushMasterStoreRequest.Builder request = FlushMasterStoreRequest.newBuilder();
+    return this.<Void> newMasterCaller()
+      .action(((controller, stub) -> this.<FlushMasterStoreRequest, FlushMasterStoreResponse,
+        Void> call(controller, stub, request.build(),
+          (s, c, req, done) -> s.flushMasterStore(c, req, done), resp -> null)))
+      .call();
+  }
 }
diff --git a/hbase-protocol-shaded/src/main/protobuf/server/master/Master.proto b/hbase-protocol-shaded/src/main/protobuf/server/master/Master.proto
index 94a434755cf..257abe8f11c 100644
--- a/hbase-protocol-shaded/src/main/protobuf/server/master/Master.proto
+++ b/hbase-protocol-shaded/src/main/protobuf/server/master/Master.proto
@@ -758,6 +758,9 @@ message ModifyColumnStoreFileTrackerResponse {
   optional uint64 proc_id = 1;
 }
 
+message FlushMasterStoreRequest {}
+message FlushMasterStoreResponse {}
+
 service MasterService {
   /** Used by the client to get the number of regions that have received the updated schema */
   rpc GetSchemaAlterStatus(GetSchemaAlterStatusRequest)
@@ -1197,6 +1200,9 @@ service MasterService {
 
   rpc ModifyColumnStoreFileTracker(ModifyColumnStoreFileTrackerRequest)
     returns(ModifyColumnStoreFileTrackerResponse);
+
+  rpc FlushMasterStore(FlushMasterStoreRequest)
+    returns(FlushMasterStoreResponse);
 }
 
 // HBCK Service definitions.
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
index 8a7cd9cfc6b..ad381dd4ef3 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
@@ -1000,6 +1000,22 @@ public interface MasterObserver {
     final TableName tableName) throws IOException {
   }
 
+  /**
+   * Called before the master local region memstore is flushed to disk.
+   * @param ctx the environment to interact with the framework and master
+   */
+  default void preMasterStoreFlush(final ObserverContext<MasterCoprocessorEnvironment> ctx)
+    throws IOException {
+  }
+
+  /**
+   * Called after the master local region memstore is flushed to disk.
+   * @param ctx the environment to interact with the framework and master
+   */
+  default void postMasterStoreFlush(final ObserverContext<MasterCoprocessorEnvironment> ctx)
+    throws IOException {
+  }
+
   /**
    * Called before the quota for the user is stored.
    * @param ctx      the environment to interact with the framework and master
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
index cd9d2db5946..c9556a80ed8 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
@@ -4225,6 +4225,26 @@ public class HMaster extends HBaseServerBase<MasterRpcServices> implements Maste
     return metaRegionLocationCache.getMetaRegionLocations();
   }
 
+  @Override
+  public void flushMasterStore() throws IOException {
+    LOG.info("Force flush master local region.");
+    if (this.cpHost != null) {
+      try {
+        cpHost.preMasterStoreFlush();
+      } catch (IOException ioe) {
+        LOG.error("Error invoking master coprocessor preMasterStoreFlush()", ioe);
+      }
+    }
+    masterRegion.flush(true);
+    if (this.cpHost != null) {
+      try {
+        cpHost.postMasterStoreFlush();
+      } catch (IOException ioe) {
+        LOG.error("Error invoking master coprocessor postMasterStoreFlush()", ioe);
+      }
+    }
+  }
+
   public Collection<ServerName> getLiveRegionServers() {
     return regionServerTracker.getRegionServers();
   }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
index 4a1aeb652fa..6295fa63d50 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
@@ -1218,6 +1218,24 @@ public class MasterCoprocessorHost
     });
   }
 
+  public void preMasterStoreFlush() throws IOException {
+    execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
+      @Override
+      public void call(MasterObserver observer) throws IOException {
+        observer.preMasterStoreFlush(this);
+      }
+    });
+  }
+
+  public void postMasterStoreFlush() throws IOException {
+    execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
+      @Override
+      public void call(MasterObserver observer) throws IOException {
+        observer.postMasterStoreFlush(this);
+      }
+    });
+  }
+
   public void preSetUserQuota(final String user, final GlobalQuotaSettings quotas)
     throws IOException {
     execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
index 8323285ee4b..e209e561f37 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
@@ -230,6 +230,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ExecProced
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ExecProcedureResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.FixMetaRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.FixMetaResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.FlushMasterStoreRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.FlushMasterStoreResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetClusterStatusRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetClusterStatusResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetCompletedSnapshotsRequest;
@@ -3469,4 +3471,16 @@ public class MasterRpcServices extends HBaseRpcServicesBase<HMaster>
     ReplicateWALEntryRequest request) throws ServiceException {
     throw new ServiceException(new DoNotRetryIOException("Unsupported method on master"));
   }
+
+  @Override
+  public FlushMasterStoreResponse flushMasterStore(RpcController controller,
+    FlushMasterStoreRequest request) throws ServiceException {
+    rpcPreCheck("flushMasterStore");
+    try {
+      server.flushMasterStore();
+    } catch (IOException ioe) {
+      throw new ServiceException(ioe);
+    }
+    return FlushMasterStoreResponse.newBuilder().build();
+  }
 }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java
index 8aaf2c28d59..d813b39863e 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java
@@ -510,4 +510,9 @@ public interface MasterServices extends Server {
    * We need to get this in MTP to tell the syncer the new meta replica count.
    */
   MetaLocationSyncer getMetaLocationSyncer();
+
+  /**
+   * Flush master local region
+   */
+  void flushMasterStore() throws IOException;
 }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/region/MasterRegion.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/region/MasterRegion.java
index b8bdc1250af..5ed0df0aa58 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/region/MasterRegion.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/region/MasterRegion.java
@@ -161,10 +161,11 @@ public final class MasterRegion {
     return region.getScanner(scan);
   }
 
-  @RestrictedApi(explanation = "Should only be called in tests", link = "",
-      allowedOnPath = ".*/src/test/.*")
   public FlushResult flush(boolean force) throws IOException {
-    return region.flush(force);
+    flusherAndCompactor.resetChangesAfterLastFlush();
+    FlushResult flushResult = region.flush(force);
+    flusherAndCompactor.recordLastFlushTime();
+    return flushResult;
   }
 
   @RestrictedApi(explanation = "Should only be called in tests", link = "",
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/region/MasterRegionFlusherAndCompactor.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/region/MasterRegionFlusherAndCompactor.java
index 2e970ae4b93..3d4bfea146e 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/region/MasterRegionFlusherAndCompactor.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/region/MasterRegionFlusherAndCompactor.java
@@ -180,7 +180,7 @@ class MasterRegionFlusherAndCompactor implements Closeable {
   }
 
   private void flushLoop() {
-    lastFlushTime = EnvironmentEdgeManager.currentTime();
+    recordLastFlushTime();
     while (!closed) {
       flushLock.lock();
       try {
@@ -202,10 +202,10 @@ class MasterRegionFlusherAndCompactor implements Closeable {
         flushLock.unlock();
       }
       assert flushRequest;
-      changesAfterLastFlush.set(0);
+      resetChangesAfterLastFlush();
       try {
         region.flush(true);
-        lastFlushTime = EnvironmentEdgeManager.currentTime();
+        recordLastFlushTime();
       } catch (IOException e) {
         LOG.error(HBaseMarkers.FATAL, "Failed to flush master local region, aborting...", e);
         abortable.abort("Failed to flush master local region", e);
@@ -263,6 +263,14 @@ class MasterRegionFlusherAndCompactor implements Closeable {
     }
   }
 
+  void resetChangesAfterLastFlush() {
+    changesAfterLastFlush.set(0);
+  }
+
+  void recordLastFlushTime() {
+    lastFlushTime = EnvironmentEdgeManager.currentTime();
+  }
+
   @Override
   public void close() {
     closed = true;
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
index bc7535cde9a..9e65e58a56d 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
@@ -189,6 +189,8 @@ public class TestMasterObserver {
     private boolean postRequestLockCalled;
     private boolean preLockHeartbeatCalled;
     private boolean postLockHeartbeatCalled;
+    private boolean preMasterStoreFlushCalled;
+    private boolean postMasterStoreFlushCalled;
 
     public void resetStates() {
       preCreateTableRegionInfosCalled = false;
@@ -280,6 +282,8 @@ public class TestMasterObserver {
       postRequestLockCalled = false;
       preLockHeartbeatCalled = false;
       postLockHeartbeatCalled = false;
+      preMasterStoreFlushCalled = false;
+      postMasterStoreFlushCalled = false;
     }
 
     @Override
@@ -1045,6 +1049,18 @@ public class TestMasterObserver {
       TableName tableName) throws IOException {
     }
 
+    @Override
+    public void preMasterStoreFlush(ObserverContext<MasterCoprocessorEnvironment> ctx)
+      throws IOException {
+      preMasterStoreFlushCalled = true;
+    }
+
+    @Override
+    public void postMasterStoreFlush(ObserverContext<MasterCoprocessorEnvironment> ctx)
+      throws IOException {
+      postMasterStoreFlushCalled = true;
+    }
+
     @Override
     public void preSetUserQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
       final String userName, final GlobalQuotaSettings quotas) throws IOException {
@@ -1680,4 +1696,23 @@ public class TestMasterObserver {
     ProcedureTestingUtility.waitNoProcedureRunning(master.getMasterProcedureExecutor());
     ProcedureTestingUtility.assertProcNotFailed(master.getMasterProcedureExecutor(), procId);
   }
+
+  @Test
+  public void testMasterStoreOperations() throws Exception {
+    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
+    HMaster master = cluster.getMaster();
+    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
+    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
+    cp.resetStates();
+    assertFalse("No master store flush call", cp.preMasterStoreFlushCalled);
+    assertFalse("No master store flush call", cp.postMasterStoreFlushCalled);
+
+    try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
+      Admin admin = connection.getAdmin()) {
+      admin.flushMasterStore();
+
+      assertTrue("Master store flush called", cp.preMasterStoreFlushCalled);
+      assertTrue("Master store flush called", cp.postMasterStoreFlushCalled);
+    }
+  }
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java
index 6a42f66e927..bc3969ffd51 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java
@@ -503,6 +503,10 @@ public class MockNoopMasterServices implements MasterServices {
     return null;
   }
 
+  @Override
+  public void flushMasterStore() {
+  }
+
   @Override
   public long modifyTableStoreFileTracker(TableName tableName, String dstSFT, long nonceGroup,
     long nonce) throws IOException {
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/region/TestMasterRegionFlush.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/region/TestMasterRegionFlush.java
index 4a8933d0031..b0f1a202779 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/region/TestMasterRegionFlush.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/region/TestMasterRegionFlush.java
@@ -148,6 +148,5 @@ public class TestMasterRegionFlush {
     assertEquals(1, flushCalled.get());
     Thread.sleep(1000);
     assertEquals(2, flushCalled.get());
-
   }
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdmin.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdmin.java
index 27aabe51743..3c0658455f3 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdmin.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdmin.java
@@ -934,4 +934,9 @@ public class VerifyingRSGroupAdmin implements Admin, Closeable {
     throws IOException {
     return admin.modifyTableStoreFileTrackerAsync(tableName, dstSFT);
   }
+
+  @Override
+  public void flushMasterStore() throws IOException {
+    admin.flushMasterStore();
+  }
 }
diff --git a/hbase-shell/src/main/ruby/hbase/admin.rb b/hbase-shell/src/main/ruby/hbase/admin.rb
index 9952cff60d6..e90e37c4bc6 100644
--- a/hbase-shell/src/main/ruby/hbase/admin.rb
+++ b/hbase-shell/src/main/ruby/hbase/admin.rb
@@ -1868,11 +1868,17 @@ module Hbase
       @admin.modifyTableStoreFileTracker(tableName, sft)
     end
 
-     #----------------------------------------------------------------------------------------------
+    #----------------------------------------------------------------------------------------------
     # Change table column family's sft
     def modify_table_family_sft(tableName, family_bytes, sft)
       @admin.modifyColumnFamilyStoreFileTracker(tableName, family_bytes, sft)
     end
+
+    #----------------------------------------------------------------------------------------------
+    # Flush master local region
+    def flush_master_store()
+      @admin.flushMasterStore()
+    end
   end
   # rubocop:enable Metrics/ClassLength
 end
diff --git a/hbase-shell/src/main/ruby/shell.rb b/hbase-shell/src/main/ruby/shell.rb
index 38a6791015f..4eb629b8cc1 100644
--- a/hbase-shell/src/main/ruby/shell.rb
+++ b/hbase-shell/src/main/ruby/shell.rb
@@ -446,6 +446,7 @@ Shell.load_command_group(
     compact
     compaction_switch
     flush
+    flush_master_store
     get_balancer_decisions
     get_balancer_rejections
     get_slowlog_responses
diff --git a/hbase-shell/src/main/ruby/shell/commands/flush_master_store.rb b/hbase-shell/src/main/ruby/shell/commands/flush_master_store.rb
new file mode 100644
index 00000000000..91b8961fffa
--- /dev/null
+++ b/hbase-shell/src/main/ruby/shell/commands/flush_master_store.rb
@@ -0,0 +1,37 @@
+#
+#
+# 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.
+#
+
+module Shell
+  module Commands
+    class FlushMasterStore < Command
+      def help
+        <<-EOF
+Flush master local region.
+For example:
+
+  hbase> flush_master_store
+EOF
+      end
+
+      def command()
+        admin.flush_master_store()
+      end
+    end
+  end
+end
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java
index 3c7586f852d..13a1b9920ec 100644
--- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java
@@ -1309,4 +1309,9 @@ public class ThriftAdmin implements Admin {
     throw new NotImplementedException(
       "modifyTableStoreFileTrackerAsync not supported in ThriftAdmin");
   }
+
+  @Override
+  public void flushMasterStore() throws IOException {
+    throw new NotImplementedException("flushMasterStore not supported in ThriftAdmin");
+  }
 }