You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by gi...@apache.org on 2025/03/17 14:48:08 UTC

(hbase-site) branch asf-site updated: Published site at 47d2aa53cb331d478e21147c83d5284a870d6d5c.

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

git-site-role pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/hbase-site.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new e645d536b36 Published site at 47d2aa53cb331d478e21147c83d5284a870d6d5c.
e645d536b36 is described below

commit e645d536b36f65508a7e41fa4d7c169d1e8dbf83
Author: jenkins <bu...@apache.org>
AuthorDate: Mon Mar 17 14:47:41 2025 +0000

    Published site at 47d2aa53cb331d478e21147c83d5284a870d6d5c.
---
 acid-semantics.html                                |     2 +-
 apache_hbase_reference_guide.pdf                   |     4 +-
 apidocs/index-all.html                             |    35 +-
 apidocs/member-search-index.js                     |     2 +-
 .../hbase/regionserver/class-use/HStore.html       |     3 +-
 .../hbase/regionserver/class-use/HStoreFile.html   |     1 +
 .../throttle/class-use/ThroughputController.html   |     3 +-
 .../hadoop/hbase/security/class-use/User.html      |     3 +-
 .../regionserver/HRegion.BulkLoadListener.html     | 13009 ++++++++++---------
 .../regionserver/HRegion.FlushResult.Result.html   | 13009 ++++++++++---------
 .../hbase/regionserver/HRegion.FlushResult.html    | 13009 ++++++++++---------
 .../regionserver/HRegion.FlushResultImpl.html      | 13009 ++++++++++---------
 .../regionserver/HRegion.PrepareFlushResult.html   | 13009 ++++++++++---------
 .../hbase/regionserver/HRegion.RowLockImpl.html    | 13009 ++++++++++---------
 .../apache/hadoop/hbase/regionserver/HRegion.html  | 13009 ++++++++++---------
 .../apache/hadoop/hbase/regionserver/HStore.html   |  2636 ++--
 .../hadoop/hbase/regionserver/StoreEngine.html     |  1006 +-
 book.html                                          |     2 +-
 bulk-loads.html                                    |     2 +-
 checkstyle-aggregate.html                          |  4711 +++----
 checkstyle.rss                                     |   660 +-
 coc.html                                           |     2 +-
 dependencies.html                                  |     2 +-
 dependency-convergence.html                        |     2 +-
 dependency-info.html                               |     2 +-
 dependency-management.html                         |     2 +-
 devapidocs/constant-values.html                    |     6 +
 devapidocs/index-all.html                          |    17 +-
 devapidocs/member-search-index.js                  |     2 +-
 .../apache/hadoop/hbase/class-use/TableName.html   |     4 +-
 ...seAdmin.AddColumnFamilyProcedureBiConsumer.html |     6 +-
 ...seAdmin.CreateNamespaceProcedureBiConsumer.html |     6 +-
 ...cHBaseAdmin.CreateTableProcedureBiConsumer.html |     6 +-
 ...dmin.DeleteColumnFamilyProcedureBiConsumer.html |     6 +-
 ...seAdmin.DeleteNamespaceProcedureBiConsumer.html |     6 +-
 ...cHBaseAdmin.DeleteTableProcedureBiConsumer.html |     8 +-
 ...HBaseAdmin.DisableTableProcedureBiConsumer.html |     6 +-
 ...cHBaseAdmin.EnableTableProcedureBiConsumer.html |     6 +-
 ...ncHBaseAdmin.FlushTableProcedureBiConsumer.html |     6 +-
 ...eAdmin.MergeTableRegionProcedureBiConsumer.html |     6 +-
 ...dmin.ModifyColumnFamilyProcedureBiConsumer.html |     6 +-
 ...nFamilyStoreFileTrackerProcedureBiConsumer.html |     6 +-
 ...seAdmin.ModifyNamespaceProcedureBiConsumer.html |     6 +-
 ...cHBaseAdmin.ModifyTableProcedureBiConsumer.html |     6 +-
 ...fyTableStoreFileTrackerProcedureBiConsumer.html |     6 +-
 ...yncHBaseAdmin.NamespaceProcedureBiConsumer.html |    14 +-
 .../RawAsyncHBaseAdmin.ProcedureBiConsumer.html    |    10 +-
 ...cHBaseAdmin.ReplicationProcedureBiConsumer.html |    14 +-
 ...syncHBaseAdmin.SnapshotProcedureBiConsumer.html |     6 +-
 ...eAdmin.SplitTableRegionProcedureBiConsumer.html |     6 +-
 ...awAsyncHBaseAdmin.TableProcedureBiConsumer.html |    14 +-
 ...aseAdmin.TruncateRegionProcedureBiConsumer.html |     6 +-
 ...BaseAdmin.TruncateTableProcedureBiConsumer.html |     6 +-
 .../hadoop/hbase/client/RawAsyncHBaseAdmin.html    |   420 +-
 .../hbase/client/class-use/TableState.State.html   |     4 +-
 .../hadoop/hbase/client/class-use/TableState.html  |    26 +-
 .../apache/hadoop/hbase/mob/MobStoreEngine.html    |     2 +-
 .../hbase/regionserver/DateTieredStoreEngine.html  |     2 +-
 .../hbase/regionserver/DefaultStoreEngine.html     |     2 +-
 .../HRegion.BatchOperation.Visitor.html            |     4 +-
 .../hbase/regionserver/HRegion.BatchOperation.html |    88 +-
 .../regionserver/HRegion.BulkLoadListener.html     |     8 +-
 .../regionserver/HRegion.FlushResult.Result.html   |    16 +-
 .../hbase/regionserver/HRegion.FlushResult.html    |     8 +-
 .../HRegion.MutationBatchOperation.html            |    72 +-
 .../regionserver/HRegion.ReplayBatchOperation.html |    34 +-
 .../hbase/regionserver/HRegion.RowLockContext.html |    28 +-
 .../hbase/regionserver/HRegion.RowLockImpl.html    |    16 +-
 .../apache/hadoop/hbase/regionserver/HRegion.html  |   522 +-
 .../regionserver/HStore.StoreFlusherImpl.html      |    36 +-
 .../apache/hadoop/hbase/regionserver/HStore.html   |   232 +-
 .../hadoop/hbase/regionserver/StoreEngine.html     |   154 +-
 .../hbase/regionserver/StripeStoreEngine.html      |     2 +-
 .../hbase/regionserver/class-use/HStore.html       |     3 +-
 .../hbase/regionserver/class-use/HStoreFile.html   |     3 +-
 .../hbase/regionserver/class-use/StoreFlusher.html |     2 +-
 .../compactions/class-use/CompactionContext.html   |     3 +-
 .../throttle/class-use/ThroughputController.html   |     3 +-
 .../access/AuthManager.PermissionCache.html        |    19 +-
 .../hadoop/hbase/security/access/AuthManager.html  |   129 +-
 .../class-use/AuthManager.PermissionCache.html     |     7 +-
 .../hadoop/hbase/security/class-use/User.html      |     3 +-
 ...seAdmin.AddColumnFamilyProcedureBiConsumer.html |  7522 ++++++-----
 .../client/RawAsyncHBaseAdmin.AdminRpcCall.html    |  7522 ++++++-----
 .../hbase/client/RawAsyncHBaseAdmin.Converter.html |  7522 ++++++-----
 ...seAdmin.CreateNamespaceProcedureBiConsumer.html |  7522 ++++++-----
 ...cHBaseAdmin.CreateTableProcedureBiConsumer.html |  7522 ++++++-----
 ...dmin.DeleteColumnFamilyProcedureBiConsumer.html |  7522 ++++++-----
 ...seAdmin.DeleteNamespaceProcedureBiConsumer.html |  7522 ++++++-----
 ...cHBaseAdmin.DeleteTableProcedureBiConsumer.html |  7522 ++++++-----
 ...HBaseAdmin.DisableTableProcedureBiConsumer.html |  7522 ++++++-----
 ...cHBaseAdmin.EnableTableProcedureBiConsumer.html |  7522 ++++++-----
 ...ncHBaseAdmin.FlushTableProcedureBiConsumer.html |  7522 ++++++-----
 .../client/RawAsyncHBaseAdmin.MasterRpcCall.html   |  7522 ++++++-----
 ...eAdmin.MergeTableRegionProcedureBiConsumer.html |  7522 ++++++-----
 ...dmin.ModifyColumnFamilyProcedureBiConsumer.html |  7522 ++++++-----
 ...nFamilyStoreFileTrackerProcedureBiConsumer.html |  7522 ++++++-----
 ...seAdmin.ModifyNamespaceProcedureBiConsumer.html |  7522 ++++++-----
 ...cHBaseAdmin.ModifyTableProcedureBiConsumer.html |  7522 ++++++-----
 ...fyTableStoreFileTrackerProcedureBiConsumer.html |  7522 ++++++-----
 ...yncHBaseAdmin.NamespaceProcedureBiConsumer.html |  7522 ++++++-----
 .../RawAsyncHBaseAdmin.ProcedureBiConsumer.html    |  7522 ++++++-----
 ...cHBaseAdmin.ReplicationProcedureBiConsumer.html |  7522 ++++++-----
 ...syncHBaseAdmin.SnapshotProcedureBiConsumer.html |  7522 ++++++-----
 ...eAdmin.SplitTableRegionProcedureBiConsumer.html |  7522 ++++++-----
 ...awAsyncHBaseAdmin.TableProcedureBiConsumer.html |  7522 ++++++-----
 ...aseAdmin.TruncateRegionProcedureBiConsumer.html |  7522 ++++++-----
 ...BaseAdmin.TruncateTableProcedureBiConsumer.html |  7522 ++++++-----
 .../hadoop/hbase/client/RawAsyncHBaseAdmin.html    |  7522 ++++++-----
 .../HRegion.BatchOperation.Visitor.html            | 13009 ++++++++++---------
 .../hbase/regionserver/HRegion.BatchOperation.html | 13009 ++++++++++---------
 .../regionserver/HRegion.BulkLoadListener.html     | 13009 ++++++++++---------
 .../regionserver/HRegion.FlushResult.Result.html   | 13009 ++++++++++---------
 .../hbase/regionserver/HRegion.FlushResult.html    | 13009 ++++++++++---------
 .../regionserver/HRegion.FlushResultImpl.html      | 13009 ++++++++++---------
 .../HRegion.MutationBatchOperation.html            | 13009 ++++++++++---------
 .../HRegion.ObservedExceptionsInBatch.html         | 13009 ++++++++++---------
 .../regionserver/HRegion.PrepareFlushResult.html   | 13009 ++++++++++---------
 .../regionserver/HRegion.ReplayBatchOperation.html | 13009 ++++++++++---------
 .../hbase/regionserver/HRegion.RowLockContext.html | 13009 ++++++++++---------
 .../hbase/regionserver/HRegion.RowLockImpl.html    | 13009 ++++++++++---------
 .../hbase/regionserver/HRegion.WriteState.html     | 13009 ++++++++++---------
 .../apache/hadoop/hbase/regionserver/HRegion.html  | 13009 ++++++++++---------
 .../HStore.StoreFileWriterCreationTracker.html     |  2636 ++--
 .../regionserver/HStore.StoreFlusherImpl.html      |  2636 ++--
 .../apache/hadoop/hbase/regionserver/HStore.html   |  2636 ++--
 .../hadoop/hbase/regionserver/StoreEngine.html     |  1006 +-
 .../access/AuthManager.PermissionCache.html        |   819 +-
 .../hadoop/hbase/security/access/AuthManager.html  |   819 +-
 downloads.html                                     |     2 +-
 export_control.html                                |     2 +-
 index.html                                         |     2 +-
 issue-management.html                              |     2 +-
 licenses.html                                      |     2 +-
 mailing-lists.html                                 |     2 +-
 metrics.html                                       |     2 +-
 old_news.html                                      |     2 +-
 plugin-management.html                             |     2 +-
 plugins.html                                       |     2 +-
 poweredbyhbase.html                                |     2 +-
 project-info.html                                  |     2 +-
 project-reports.html                               |     2 +-
 pseudo-distributed.html                            |     2 +-
 replication.html                                   |     2 +-
 resources.html                                     |     2 +-
 scm.html                                           |     2 +-
 sponsors.html                                      |     2 +-
 summary.html                                       |     2 +-
 supportingprojects.html                            |     2 +-
 team.html                                          |     2 +-
 testapidocs/allclasses-index.html                  |   652 +-
 testapidocs/index-all.html                         |   110 +-
 testapidocs/member-search-index.js                 |     2 +-
 .../hadoop/hbase/class-use/HBaseClassTestRule.html |    19 +-
 .../class-use/TestTableEnableDisableError.html     |    62 +
 .../hadoop/hbase/client/package-summary.html       |    30 +-
 .../apache/hadoop/hbase/client/package-tree.html   |     1 +
 testapidocs/overview-tree.html                     |     1 +
 .../hbase/client/TestTableEnableDisableError.html  |   169 +
 ...ngStoreMockMaker.BlockingCompactionContext.html |  1751 +--
 .../TestCompaction.BlockingStoreMockMaker.html     |  1751 +--
 .../TestCompaction.DummyCompactor.html             |  1751 +--
 .../hbase/regionserver/TestCompaction.Tracker.html |  1751 +--
 .../TestCompaction.WaitThroughPutController.html   |  1751 +--
 .../hadoop/hbase/regionserver/TestCompaction.html  |  1751 +--
 testapidocs/type-search-index.js                   |     2 +-
 testdevapidocs/allclasses-index.html               |  1072 +-
 testdevapidocs/index-all.html                      |   102 +-
 testdevapidocs/member-search-index.js              |     2 +-
 .../hadoop/hbase/class-use/HBaseClassTestRule.html |    19 +-
 .../TestTableEnableDisableError.html}              |   108 +-
 .../class-use/TestTableEnableDisableError.html     |    62 +
 .../hadoop/hbase/client/package-summary.html       |    34 +-
 .../apache/hadoop/hbase/client/package-tree.html   |     1 +
 ...ngStoreMockMaker.BlockingCompactionContext.html |    14 +-
 .../TestCompaction.BlockingStoreMockMaker.html     |    18 +-
 .../TestCompaction.DummyCompactor.html             |     4 +-
 ...ction.StoreMockMaker.TestCompactionContext.html |    12 +-
 .../TestCompaction.StoreMockMaker.html             |    18 +-
 .../hbase/regionserver/TestCompaction.Tracker.html |     8 +-
 .../TestCompaction.WaitThroughPutController.html   |     6 +-
 .../hadoop/hbase/regionserver/TestCompaction.html  |   117 +-
 .../TestCompactionWithCoprocessor.html             |     2 +-
 .../security/access/TestZKPermissionWatcher.html   |    54 +
 testdevapidocs/overview-tree.html                  |     1 +
 .../hbase/client/TestTableEnableDisableError.html  |   169 +
 ...ngStoreMockMaker.BlockingCompactionContext.html |  1751 +--
 .../TestCompaction.BlockingStoreMockMaker.html     |  1751 +--
 .../TestCompaction.DummyCompactor.html             |  1751 +--
 ...ction.StoreMockMaker.TestCompactionContext.html |  1751 +--
 .../TestCompaction.StoreMockMaker.html             |  1751 +--
 .../hbase/regionserver/TestCompaction.Tracker.html |  1751 +--
 .../TestCompaction.WaitThroughPutController.html   |  1751 +--
 .../hadoop/hbase/regionserver/TestCompaction.html  |  1751 +--
 .../security/access/TestZKPermissionWatcher.html   |   163 +-
 testdevapidocs/type-search-index.js                |     2 +-
 196 files changed, 264327 insertions(+), 261225 deletions(-)

diff --git a/acid-semantics.html b/acid-semantics.html
index 390271c674a..3703c3f2c2f 100644
--- a/acid-semantics.html
+++ b/acid-semantics.html
@@ -469,7 +469,7 @@
         All other marks mentioned may be trademarks or registered trademarks of their respective owners.
       </div>
       <div style="float: right">
-        Last Published: 2025-03-16
+        Last Published: 2025-03-17
       </div>
         </div>
         <p id="poweredBy" class="pull-right"><a href="http://maven.apache.org/" title="Built by Maven" class="poweredBy"><img class="builtBy" alt="Built by Maven" src="./images/logos/maven-feather.png" /></a>
diff --git a/apache_hbase_reference_guide.pdf b/apache_hbase_reference_guide.pdf
index c4fc01f5416..88c089a17a0 100644
--- a/apache_hbase_reference_guide.pdf
+++ b/apache_hbase_reference_guide.pdf
@@ -5,8 +5,8 @@
 /Author (Apache HBase Team)
 /Creator (Asciidoctor PDF 2.0.6, based on Prawn 2.4.0)
 /Producer (Apache HBase Team)
-/ModDate (D:20250316143212+00'00')
-/CreationDate (D:20250316144812+00'00')
+/ModDate (D:20250317143039+00'00')
+/CreationDate (D:20250317144433+00'00')
 >>
 endobj
 2 0 obj
diff --git a/apidocs/index-all.html b/apidocs/index-all.html
index 434a401f2dc..8e08f52f61c 100644
--- a/apidocs/index-all.html
+++ b/apidocs/index-all.html
@@ -5118,7 +5118,7 @@ loadScripts(document, 'script');</script>
 <dd>&nbsp;</dd>
 <dt>call(O) - Method in class org.apache.hadoop.hbase.coprocessor.CoprocessorHost.ObserverOperationWithResult</dt>
 <dd>&nbsp;</dd>
-<dt>call(AbstractRpcBasedConnectionRegistry.Callable&lt;T&gt;, Predicate&lt;T&gt;, String) - Method in class org.apache.hadoop.hbase.client.MasterRegistry</dt>
+<dt>call(AbstractRpcBasedConnectionRegistry.Callable&lt;T&gt;, Predicate&lt;T&gt;, String) - Method in class org.apache.hadoop.hbase.client.RpcConnectionRegistry</dt>
 <dd>&nbsp;</dd>
 <dt>call(HBaseRpcController, AdminProtos.AdminService.Interface) - Method in interface org.apache.hadoop.hbase.client.AsyncAdminRequestRetryingCaller.Callable</dt>
 <dd>&nbsp;</dd>
@@ -7172,7 +7172,7 @@ loadScripts(document, 'script');</script>
 </dd>
 <dt>close() - Method in class org.apache.hadoop.hbase.chaos.ChaosAgent</dt>
 <dd>&nbsp;</dd>
-<dt>close() - Method in class org.apache.hadoop.hbase.client.MasterRegistry</dt>
+<dt>close() - Method in class org.apache.hadoop.hbase.client.RpcConnectionRegistry</dt>
 <dd>&nbsp;</dd>
 <dt>close() - Method in interface org.apache.hadoop.hbase.client.Admin</dt>
 <dd>&nbsp;</dd>
@@ -8058,7 +8058,7 @@ loadScripts(document, 'script');</script>
 <dd>
 <div class="block">Move the file from a build/temp location to the main family store directory.</div>
 </dd>
-<dt>commitStoreFiles(List&lt;Path&gt;, boolean) - Method in class org.apache.hadoop.hbase.regionserver.StoreEngine</dt>
+<dt>commitStoreFiles(List&lt;Path&gt;, boolean, boolean) - Method in class org.apache.hadoop.hbase.regionserver.StoreEngine</dt>
 <dd>
 <div class="block">Commit the given <code>files</code>.</div>
 </dd>
@@ -8115,7 +8115,8 @@ loadScripts(document, 'script');</script>
 </dd>
 <dt>compact(CompactionContext, HStore, ThroughputController, User) - Method in class org.apache.hadoop.hbase.regionserver.HRegion</dt>
 <dd>
-<div class="block">We are trying to remove / relax the region read lock for compaction.</div>
+<div class="block">
+ We are trying to remove / relax the region read lock for compaction.</div>
 </dd>
 <dt>compact(CompactionContext, ThroughputController, User) - Method in class org.apache.hadoop.hbase.regionserver.HStore</dt>
 <dd>
@@ -9235,7 +9236,7 @@ loadScripts(document, 'script');</script>
 <dd>&nbsp;</dd>
 <dt>conf - Variable in class org.apache.hadoop.hbase.regionserver.StoreFileReader</dt>
 <dd>&nbsp;</dd>
-<dt>conf - Variable in class org.apache.hadoop.hbase.regionserver.StripeStoreFlusher</dt>
+<dt>conf - Variable in class org.apache.hadoop.hbase.regionserver.DefaultStoreFlusher</dt>
 <dd>&nbsp;</dd>
 <dt>conf - Variable in class org.apache.hadoop.hbase.regionserver.wal.AbstractFSWAL</dt>
 <dd>
@@ -11905,7 +11906,7 @@ loadScripts(document, 'script');</script>
 <dd>
 <div class="block">Create a new Scan with a cursor.</div>
 </dd>
-<dt>createScanner(List&lt;KeyValueScanner&gt;, FlushLifeCycleTracker) - Method in class org.apache.hadoop.hbase.regionserver.StripeStoreFlusher</dt>
+<dt>createScanner(List&lt;KeyValueScanner&gt;, FlushLifeCycleTracker) - Method in class org.apache.hadoop.hbase.regionserver.DefaultStoreFlusher</dt>
 <dd>
 <div class="block">Creates the scanner for flushing snapshot.</div>
 </dd>
@@ -12441,7 +12442,7 @@ loadScripts(document, 'script');</script>
 <dd>
 <div class="block">Create a writer for writing new store files.</div>
 </dd>
-<dt>createWriter(MemStoreSnapshot, boolean, Consumer&lt;Path&gt;) - Method in class org.apache.hadoop.hbase.regionserver.StripeStoreFlusher</dt>
+<dt>createWriter(MemStoreSnapshot, boolean, Consumer&lt;Path&gt;) - Method in class org.apache.hadoop.hbase.regionserver.DefaultStoreFlusher</dt>
 <dd>&nbsp;</dd>
 <dt>createWriterInstance(FileSystem, Path) - Method in class org.apache.hadoop.hbase.regionserver.wal.AbstractFSWAL</dt>
 <dd>&nbsp;</dd>
@@ -18472,7 +18473,7 @@ loadScripts(document, 'script');</script>
 <dd>&nbsp;</dd>
 <dt>finalizeWriter(StoreFileWriter, long, MonitoredTask) - Method in class org.apache.hadoop.hbase.mob.DefaultMobStoreFlusher</dt>
 <dd>&nbsp;</dd>
-<dt>finalizeWriter(StoreFileWriter, long, MonitoredTask) - Method in class org.apache.hadoop.hbase.regionserver.StripeStoreFlusher</dt>
+<dt>finalizeWriter(StoreFileWriter, long, MonitoredTask) - Method in class org.apache.hadoop.hbase.regionserver.DefaultStoreFlusher</dt>
 <dd>&nbsp;</dd>
 <dt>findArchivedLog(Path, Configuration) - Static method in class org.apache.hadoop.hbase.wal.AbstractFSWALProvider</dt>
 <dd>
@@ -19981,7 +19982,7 @@ loadScripts(document, 'script');</script>
 <dd>&nbsp;</dd>
 <dt>getActiveLogFiles() - Static method in class org.apache.hadoop.hbase.logging.Log4jUtils</dt>
 <dd>&nbsp;</dd>
-<dt>getActiveMaster() - Method in class org.apache.hadoop.hbase.client.MasterRegistry</dt>
+<dt>getActiveMaster() - Method in class org.apache.hadoop.hbase.client.RpcConnectionRegistry</dt>
 <dd>&nbsp;</dd>
 <dt>getActiveMaster() - Method in interface org.apache.hadoop.hbase.client.ConnectionRegistry</dt>
 <dd>
@@ -21779,7 +21780,7 @@ loadScripts(document, 'script');</script>
 <dd>
 <div class="block">Returns the cluster definition</div>
 </dd>
-<dt>getClusterId() - Method in class org.apache.hadoop.hbase.client.MasterRegistry</dt>
+<dt>getClusterId() - Method in class org.apache.hadoop.hbase.client.RpcConnectionRegistry</dt>
 <dd>&nbsp;</dd>
 <dt>getClusterId() - Method in interface org.apache.hadoop.hbase.client.Connection</dt>
 <dd>
@@ -26951,7 +26952,7 @@ loadScripts(document, 'script');</script>
 </dd>
 <dt>getMetaRegionLocationCache() - Method in class org.apache.hadoop.hbase.HBaseServerBase</dt>
 <dd>&nbsp;</dd>
-<dt>getMetaRegionLocations() - Method in class org.apache.hadoop.hbase.client.MasterRegistry</dt>
+<dt>getMetaRegionLocations() - Method in class org.apache.hadoop.hbase.client.RpcConnectionRegistry</dt>
 <dd>&nbsp;</dd>
 <dt>getMetaRegionLocations() - Method in interface org.apache.hadoop.hbase.client.ConnectionRegistry</dt>
 <dd>
@@ -33093,10 +33094,6 @@ loadScripts(document, 'script');</script>
 <dd>
 <div class="block">Returns The total size of all index blocks, not just the root level</div>
 </dd>
-<dt>getStoreFlusher() - Method in class org.apache.hadoop.hbase.regionserver.StoreEngine</dt>
-<dd>
-<div class="block">Returns Store flusher to use.</div>
-</dd>
 <dt>getStoreHomedir(Path, String, byte[]) - Static method in class org.apache.hadoop.hbase.regionserver.HRegionFileSystem</dt>
 <dd>&nbsp;</dd>
 <dt>getStoreHomedir(Path, RegionInfo, byte[]) - Static method in class org.apache.hadoop.hbase.regionserver.HRegionFileSystem</dt>
@@ -37434,7 +37431,7 @@ loadScripts(document, 'script');</script>
 <dd>&nbsp;</dd>
 <dt>HEDGED_READS_DESC - Static variable in interface org.apache.hadoop.hbase.regionserver.MetricsRegionServerSource</dt>
 <dd>&nbsp;</dd>
-<dt>HEDGED_REQS_FANOUT_DEFAULT - Static variable in class org.apache.hadoop.hbase.client.MasterRegistry</dt>
+<dt>HEDGED_REQS_FANOUT_DEFAULT - Static variable in class org.apache.hadoop.hbase.client.RpcConnectionRegistry</dt>
 <dd>
 <div class="block">Default value for the fan out of hedged requests.</div>
 </dd>
@@ -51931,7 +51928,7 @@ service.</div>
 <dd>
 <div class="block">Performs compaction on a column family with the mob flag enabled.</div>
 </dd>
-<dt>performFlush(InternalScanner, CellSink, ThroughputController) - Method in class org.apache.hadoop.hbase.regionserver.StripeStoreFlusher</dt>
+<dt>performFlush(InternalScanner, CellSink, ThroughputController) - Method in class org.apache.hadoop.hbase.regionserver.DefaultStoreFlusher</dt>
 <dd>
 <div class="block">Performs memstore flush, writing data from scanner into sink.</div>
 </dd>
@@ -68178,7 +68175,7 @@ service.</div>
 </dd>
 <dt>store - Variable in class org.apache.hadoop.hbase.io.crypto.KeyStoreKeyProvider</dt>
 <dd>&nbsp;</dd>
-<dt>store - Variable in class org.apache.hadoop.hbase.regionserver.StripeStoreFlusher</dt>
+<dt>store - Variable in class org.apache.hadoop.hbase.regionserver.DefaultStoreFlusher</dt>
 <dd>&nbsp;</dd>
 <dt>store - Variable in class org.apache.hadoop.hbase.regionserver.StoreScanner</dt>
 <dd>&nbsp;</dd>
@@ -74177,7 +74174,7 @@ service.</div>
 <dd>
 <div class="block">Verifies root directory path is a valid URI with a scheme</div>
 </dd>
-<dt>validateStoreFile(Path) - Method in class org.apache.hadoop.hbase.regionserver.StoreEngine</dt>
+<dt>validateStoreFile(Path, boolean) - Method in class org.apache.hadoop.hbase.regionserver.StoreEngine</dt>
 <dd>
 <div class="block">Validates a store file by opening and closing it.</div>
 </dd>
diff --git a/apidocs/member-search-index.js b/apidocs/member-search-index.js
index f747799849f..7b74cd0ba56 100644
--- a/apidocs/member-search-index.js
+++ b/apidocs/member-search-index.js
@@ -1 +1 @@
-memberSearchIndex = [{"p":"org.apache.hadoop.hbase.filter","c":"ParseConstants","l":"A"},{"p":"org.apache.hadoop.hbase.master","c":"RegionState.State","l":"ABNORMALLY_CLOSED"},{"p":"org.apache.hadoop.hbase.coprocessor","c":"CoprocessorHost","l":"ABORT_ON_ERROR_KEY"},{"p":"org.apache.hadoop.hdfs","c":"DummyDFSOutputStream","l":"abort()"},{"p":"org.apache.hadoop.hbase","c":"Abortable","l":"abort(String)","u":"abort(java.lang.String)"},{"p":"org.apache.hadoop.hbase","c":"Abortable","l":"abo [...]
\ No newline at end of file
+memberSearchIndex = [{"p":"org.apache.hadoop.hbase.filter","c":"ParseConstants","l":"A"},{"p":"org.apache.hadoop.hbase.master","c":"RegionState.State","l":"ABNORMALLY_CLOSED"},{"p":"org.apache.hadoop.hbase.coprocessor","c":"CoprocessorHost","l":"ABORT_ON_ERROR_KEY"},{"p":"org.apache.hadoop.hdfs","c":"DummyDFSOutputStream","l":"abort()"},{"p":"org.apache.hadoop.hbase","c":"Abortable","l":"abort(String)","u":"abort(java.lang.String)"},{"p":"org.apache.hadoop.hbase","c":"Abortable","l":"abo [...]
\ No newline at end of file
diff --git a/apidocs/org/apache/hadoop/hbase/regionserver/class-use/HStore.html b/apidocs/org/apache/hadoop/hbase/regionserver/class-use/HStore.html
index ac8f8ee8fc9..019d008787f 100644
--- a/apidocs/org/apache/hadoop/hbase/regionserver/class-use/HStore.html
+++ b/apidocs/org/apache/hadoop/hbase/regionserver/class-use/HStore.html
@@ -227,7 +227,8 @@ loadScripts(document, 'script');</script>
  org.apache.hadoop.hbase.regionserver.throttle.ThroughputController&nbsp;throughputController,
  org.apache.hadoop.hbase.security.User&nbsp;user)</code></div>
 <div class="col-last odd-row-color">
-<div class="block">We are trying to remove / relax the region read lock for compaction.</div>
+<div class="block">
+ We are trying to remove / relax the region read lock for compaction.</div>
 </div>
 <div class="col-first even-row-color"><code>static org.apache.hadoop.hbase.regionserver.StoreEngine&lt;?,<wbr>?,<wbr>?,<wbr>?&gt;</code></div>
 <div class="col-second even-row-color"><span class="type-name-label">StoreEngine.</span><code>create<wbr>(org.apache.hadoop.hbase.regionserver.HStore&nbsp;store,
diff --git a/apidocs/org/apache/hadoop/hbase/regionserver/class-use/HStoreFile.html b/apidocs/org/apache/hadoop/hbase/regionserver/class-use/HStoreFile.html
index fb73d342980..e649701ef33 100644
--- a/apidocs/org/apache/hadoop/hbase/regionserver/class-use/HStoreFile.html
+++ b/apidocs/org/apache/hadoop/hbase/regionserver/class-use/HStoreFile.html
@@ -195,6 +195,7 @@ loadScripts(document, 'script');</script>
 </div>
 <div class="col-first odd-row-color"><code><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a>&lt;org.apache.hadoop.hbase.regionserver.HStoreFile&gt;</code></div>
 <div class="col-second odd-row-color"><span class="type-name-label">StoreEngine.</span><code>commitStoreFiles<wbr>(<a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a>&lt;org.apache.hadoop.fs.Path&gt;&nbsp;files,
+ boolean&nbsp;isCompaction,
  boolean&nbsp;validate)</code></div>
 <div class="col-last odd-row-color">
 <div class="block">Commit the given <code>files</code>.</div>
diff --git a/apidocs/org/apache/hadoop/hbase/regionserver/throttle/class-use/ThroughputController.html b/apidocs/org/apache/hadoop/hbase/regionserver/throttle/class-use/ThroughputController.html
index 43203e052dc..829d37cd628 100644
--- a/apidocs/org/apache/hadoop/hbase/regionserver/throttle/class-use/ThroughputController.html
+++ b/apidocs/org/apache/hadoop/hbase/regionserver/throttle/class-use/ThroughputController.html
@@ -167,7 +167,8 @@ loadScripts(document, 'script');</script>
  org.apache.hadoop.hbase.regionserver.throttle.ThroughputController&nbsp;throughputController,
  org.apache.hadoop.hbase.security.User&nbsp;user)</code></div>
 <div class="col-last odd-row-color">
-<div class="block">We are trying to remove / relax the region read lock for compaction.</div>
+<div class="block">
+ We are trying to remove / relax the region read lock for compaction.</div>
 </div>
 <div class="col-first even-row-color"><code><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a>&lt;org.apache.hadoop.hbase.regionserver.HStoreFile&gt;</code></div>
 <div class="col-second even-row-color"><span class="type-name-label">HStore.</span><code>compact<wbr>(org.apache.hadoop.hbase.regionserver.compactions.CompactionContext&nbsp;compaction,
diff --git a/apidocs/org/apache/hadoop/hbase/security/class-use/User.html b/apidocs/org/apache/hadoop/hbase/security/class-use/User.html
index 016cc75ac1e..14bab582273 100644
--- a/apidocs/org/apache/hadoop/hbase/security/class-use/User.html
+++ b/apidocs/org/apache/hadoop/hbase/security/class-use/User.html
@@ -637,7 +637,8 @@ loadScripts(document, 'script');</script>
  org.apache.hadoop.hbase.regionserver.throttle.ThroughputController&nbsp;throughputController,
  org.apache.hadoop.hbase.security.User&nbsp;user)</code></div>
 <div class="col-last even-row-color">
-<div class="block">We are trying to remove / relax the region read lock for compaction.</div>
+<div class="block">
+ We are trying to remove / relax the region read lock for compaction.</div>
 </div>
 <div class="col-first odd-row-color"><code><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a>&lt;org.apache.hadoop.hbase.regionserver.HStoreFile&gt;</code></div>
 <div class="col-second odd-row-color"><span class="type-name-label">HStore.</span><code>compact<wbr>(org.apache.hadoop.hbase.regionserver.compactions.CompactionContext&nbsp;compaction,
diff --git a/apidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html b/apidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html
index 0881d1af293..f381a0bc77f 100644
--- a/apidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html
+++ b/apidocs/src-html/org/apache/hadoop/hbase/regionserver/HRegion.BulkLoadListener.html
@@ -2345,6571 +2345,6634 @@
 <span class="source-line-no">2332</span><span id="line-2332">  }</span>
 <span class="source-line-no">2333</span><span id="line-2333"></span>
 <span class="source-line-no">2334</span><span id="line-2334">  /**</span>
-<span class="source-line-no">2335</span><span id="line-2335">   * We are trying to remove / relax the region read lock for compaction. Let's see what are the</span>
-<span class="source-line-no">2336</span><span id="line-2336">   * potential race conditions among the operations (user scan, region split, region close and</span>
-<span class="source-line-no">2337</span><span id="line-2337">   * region bulk load). user scan ---&gt; region read lock region split --&gt; region close first --&gt;</span>
-<span class="source-line-no">2338</span><span id="line-2338">   * region write lock region close --&gt; region write lock region bulk load --&gt; region write lock</span>
-<span class="source-line-no">2339</span><span id="line-2339">   * read lock is compatible with read lock. ---&gt; no problem with user scan/read region bulk load</span>
-<span class="source-line-no">2340</span><span id="line-2340">   * does not cause problem for compaction (no consistency problem, store lock will help the store</span>
-<span class="source-line-no">2341</span><span id="line-2341">   * file accounting). They can run almost concurrently at the region level. The only remaining race</span>
-<span class="source-line-no">2342</span><span id="line-2342">   * condition is between the region close and compaction. So we will evaluate, below, how region</span>
-<span class="source-line-no">2343</span><span id="line-2343">   * close intervenes with compaction if compaction does not acquire region read lock. Here are the</span>
-<span class="source-line-no">2344</span><span id="line-2344">   * steps for compaction: 1. obtain list of StoreFile's 2. create StoreFileScanner's based on list</span>
-<span class="source-line-no">2345</span><span id="line-2345">   * from #1 3. perform compaction and save resulting files under tmp dir 4. swap in compacted files</span>
-<span class="source-line-no">2346</span><span id="line-2346">   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better For #2, we</span>
-<span class="source-line-no">2347</span><span id="line-2347">   * obtain smallest read point (for region) across all the Scanners (for both default compactor and</span>
-<span class="source-line-no">2348</span><span id="line-2348">   * stripe compactor). The read points are for user scans. Region keeps the read points for all</span>
-<span class="source-line-no">2349</span><span id="line-2349">   * currently open user scanners. Compaction needs to know the smallest read point so that during</span>
-<span class="source-line-no">2350</span><span id="line-2350">   * re-write of the hfiles, it can remove the mvcc points for the cells if their mvccs are older</span>
-<span class="source-line-no">2351</span><span id="line-2351">   * than the smallest since they are not needed anymore. This will not conflict with compaction.</span>
-<span class="source-line-no">2352</span><span id="line-2352">   * For #3, it can be performed in parallel to other operations. For #4 bulk load and compaction</span>
-<span class="source-line-no">2353</span><span id="line-2353">   * don't conflict with each other on the region level (for multi-family atomicy). Region close and</span>
-<span class="source-line-no">2354</span><span id="line-2354">   * compaction are guarded pretty well by the 'writestate'. In HRegion#doClose(), we have :</span>
-<span class="source-line-no">2355</span><span id="line-2355">   * synchronized (writestate) { // Disable compacting and flushing by background threads for this</span>
-<span class="source-line-no">2356</span><span id="line-2356">   * // region. canFlush = !writestate.readOnly; writestate.writesEnabled = false;</span>
-<span class="source-line-no">2357</span><span id="line-2357">   * LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");</span>
-<span class="source-line-no">2358</span><span id="line-2358">   * waitForFlushesAndCompactions(); } waitForFlushesAndCompactions() would wait for</span>
-<span class="source-line-no">2359</span><span id="line-2359">   * writestate.compacting to come down to 0. and in HRegion.compact() try { synchronized</span>
-<span class="source-line-no">2360</span><span id="line-2360">   * (writestate) { if (writestate.writesEnabled) { wasStateSet = true; ++writestate.compacting; }</span>
-<span class="source-line-no">2361</span><span id="line-2361">   * else { String msg = "NOT compacting region " + this + ". Writes disabled."; LOG.info(msg);</span>
-<span class="source-line-no">2362</span><span id="line-2362">   * status.abort(msg); return false; } } Also in compactor.performCompaction(): check periodically</span>
-<span class="source-line-no">2363</span><span id="line-2363">   * to see if a system stop is requested if (closeChecker != null &amp;&amp;</span>
-<span class="source-line-no">2364</span><span id="line-2364">   * closeChecker.isTimeLimit(store, now)) { progress.cancel(); return false; } if (closeChecker !=</span>
-<span class="source-line-no">2365</span><span id="line-2365">   * null &amp;&amp; closeChecker.isSizeLimit(store, len)) { progress.cancel(); return false; }</span>
-<span class="source-line-no">2366</span><span id="line-2366">   */</span>
-<span class="source-line-no">2367</span><span id="line-2367">  public boolean compact(CompactionContext compaction, HStore store,</span>
-<span class="source-line-no">2368</span><span id="line-2368">    ThroughputController throughputController, User user) throws IOException {</span>
-<span class="source-line-no">2369</span><span id="line-2369">    assert compaction != null &amp;&amp; compaction.hasSelection();</span>
-<span class="source-line-no">2370</span><span id="line-2370">    assert !compaction.getRequest().getFiles().isEmpty();</span>
-<span class="source-line-no">2371</span><span id="line-2371">    if (this.closing.get() || this.closed.get()) {</span>
-<span class="source-line-no">2372</span><span id="line-2372">      LOG.debug("Skipping compaction on " + this + " because closing/closed");</span>
-<span class="source-line-no">2373</span><span id="line-2373">      store.cancelRequestedCompaction(compaction);</span>
-<span class="source-line-no">2374</span><span id="line-2374">      return false;</span>
-<span class="source-line-no">2375</span><span id="line-2375">    }</span>
-<span class="source-line-no">2376</span><span id="line-2376"></span>
-<span class="source-line-no">2377</span><span id="line-2377">    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {</span>
-<span class="source-line-no">2378</span><span id="line-2378">      LOG.warn("Skipping major compaction on " + this</span>
-<span class="source-line-no">2379</span><span id="line-2379">        + " because this cluster is transiting sync replication state"</span>
-<span class="source-line-no">2380</span><span id="line-2380">        + " from STANDBY to DOWNGRADE_ACTIVE");</span>
-<span class="source-line-no">2381</span><span id="line-2381">      store.cancelRequestedCompaction(compaction);</span>
-<span class="source-line-no">2382</span><span id="line-2382">      return false;</span>
-<span class="source-line-no">2383</span><span id="line-2383">    }</span>
-<span class="source-line-no">2384</span><span id="line-2384"></span>
-<span class="source-line-no">2385</span><span id="line-2385">    MonitoredTask status = null;</span>
-<span class="source-line-no">2386</span><span id="line-2386">    boolean requestNeedsCancellation = true;</span>
-<span class="source-line-no">2387</span><span id="line-2387">    try {</span>
-<span class="source-line-no">2388</span><span id="line-2388">      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());</span>
-<span class="source-line-no">2389</span><span id="line-2389">      if (stores.get(cf) != store) {</span>
-<span class="source-line-no">2390</span><span id="line-2390">        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this</span>
-<span class="source-line-no">2391</span><span id="line-2391">          + " has been re-instantiated, cancel this compaction request. "</span>
-<span class="source-line-no">2392</span><span id="line-2392">          + " It may be caused by the roll back of split transaction");</span>
-<span class="source-line-no">2393</span><span id="line-2393">        return false;</span>
-<span class="source-line-no">2394</span><span id="line-2394">      }</span>
-<span class="source-line-no">2395</span><span id="line-2395"></span>
-<span class="source-line-no">2396</span><span id="line-2396">      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);</span>
-<span class="source-line-no">2397</span><span id="line-2397">      if (this.closed.get()) {</span>
-<span class="source-line-no">2398</span><span id="line-2398">        String msg = "Skipping compaction on " + this + " because closed";</span>
-<span class="source-line-no">2399</span><span id="line-2399">        LOG.debug(msg);</span>
-<span class="source-line-no">2400</span><span id="line-2400">        status.abort(msg);</span>
-<span class="source-line-no">2401</span><span id="line-2401">        return false;</span>
-<span class="source-line-no">2402</span><span id="line-2402">      }</span>
-<span class="source-line-no">2403</span><span id="line-2403">      boolean wasStateSet = false;</span>
-<span class="source-line-no">2404</span><span id="line-2404">      try {</span>
-<span class="source-line-no">2405</span><span id="line-2405">        synchronized (writestate) {</span>
-<span class="source-line-no">2406</span><span id="line-2406">          if (writestate.writesEnabled) {</span>
-<span class="source-line-no">2407</span><span id="line-2407">            wasStateSet = true;</span>
-<span class="source-line-no">2408</span><span id="line-2408">            writestate.compacting.incrementAndGet();</span>
-<span class="source-line-no">2409</span><span id="line-2409">          } else {</span>
-<span class="source-line-no">2410</span><span id="line-2410">            String msg = "NOT compacting region " + this + ". Writes disabled.";</span>
-<span class="source-line-no">2411</span><span id="line-2411">            LOG.info(msg);</span>
-<span class="source-line-no">2412</span><span id="line-2412">            status.abort(msg);</span>
-<span class="source-line-no">2413</span><span id="line-2413">            return false;</span>
-<span class="source-line-no">2414</span><span id="line-2414">          }</span>
-<span class="source-line-no">2415</span><span id="line-2415">        }</span>
-<span class="source-line-no">2416</span><span id="line-2416">        LOG.info("Starting compaction of {} in {}{}", store, this,</span>
-<span class="source-line-no">2417</span><span id="line-2417">          (compaction.getRequest().isOffPeak() ? " as an off-peak compaction" : ""));</span>
-<span class="source-line-no">2418</span><span id="line-2418">        doRegionCompactionPrep();</span>
-<span class="source-line-no">2419</span><span id="line-2419">        try {</span>
-<span class="source-line-no">2420</span><span id="line-2420">          status.setStatus("Compacting store " + store);</span>
-<span class="source-line-no">2421</span><span id="line-2421">          // We no longer need to cancel the request on the way out of this</span>
-<span class="source-line-no">2422</span><span id="line-2422">          // method because Store#compact will clean up unconditionally</span>
-<span class="source-line-no">2423</span><span id="line-2423">          requestNeedsCancellation = false;</span>
-<span class="source-line-no">2424</span><span id="line-2424">          store.compact(compaction, throughputController, user);</span>
-<span class="source-line-no">2425</span><span id="line-2425">        } catch (InterruptedIOException iioe) {</span>
-<span class="source-line-no">2426</span><span id="line-2426">          String msg = "region " + this + " compaction interrupted";</span>
-<span class="source-line-no">2427</span><span id="line-2427">          LOG.info(msg, iioe);</span>
-<span class="source-line-no">2428</span><span id="line-2428">          status.abort(msg);</span>
-<span class="source-line-no">2429</span><span id="line-2429">          return false;</span>
-<span class="source-line-no">2430</span><span id="line-2430">        }</span>
-<span class="source-line-no">2431</span><span id="line-2431">      } finally {</span>
-<span class="source-line-no">2432</span><span id="line-2432">        if (wasStateSet) {</span>
-<span class="source-line-no">2433</span><span id="line-2433">          synchronized (writestate) {</span>
-<span class="source-line-no">2434</span><span id="line-2434">            writestate.compacting.decrementAndGet();</span>
-<span class="source-line-no">2435</span><span id="line-2435">            if (writestate.compacting.get() &lt;= 0) {</span>
-<span class="source-line-no">2436</span><span id="line-2436">              writestate.notifyAll();</span>
-<span class="source-line-no">2437</span><span id="line-2437">            }</span>
-<span class="source-line-no">2438</span><span id="line-2438">          }</span>
-<span class="source-line-no">2439</span><span id="line-2439">        }</span>
-<span class="source-line-no">2440</span><span id="line-2440">      }</span>
-<span class="source-line-no">2441</span><span id="line-2441">      status.markComplete("Compaction complete");</span>
-<span class="source-line-no">2442</span><span id="line-2442">      return true;</span>
-<span class="source-line-no">2443</span><span id="line-2443">    } finally {</span>
-<span class="source-line-no">2444</span><span id="line-2444">      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);</span>
-<span class="source-line-no">2445</span><span id="line-2445">      if (status != null) {</span>
-<span class="source-line-no">2446</span><span id="line-2446">        LOG.debug("Compaction status journal for {}:\n{}", this.getRegionInfo().getEncodedName(),</span>
-<span class="source-line-no">2447</span><span id="line-2447">          status.prettyPrintJournal());</span>
-<span class="source-line-no">2448</span><span id="line-2448">        status.cleanup();</span>
-<span class="source-line-no">2449</span><span id="line-2449">      }</span>
-<span class="source-line-no">2450</span><span id="line-2450">    }</span>
-<span class="source-line-no">2451</span><span id="line-2451">  }</span>
-<span class="source-line-no">2452</span><span id="line-2452"></span>
-<span class="source-line-no">2453</span><span id="line-2453">  /**</span>
-<span class="source-line-no">2454</span><span id="line-2454">   * Flush the cache.</span>
-<span class="source-line-no">2455</span><span id="line-2455">   * &lt;p&gt;</span>
-<span class="source-line-no">2456</span><span id="line-2456">   * When this method is called the cache will be flushed unless:</span>
-<span class="source-line-no">2457</span><span id="line-2457">   * &lt;ol&gt;</span>
-<span class="source-line-no">2458</span><span id="line-2458">   * &lt;li&gt;the cache is empty&lt;/li&gt;</span>
-<span class="source-line-no">2459</span><span id="line-2459">   * &lt;li&gt;the region is closed.&lt;/li&gt;</span>
-<span class="source-line-no">2460</span><span id="line-2460">   * &lt;li&gt;a flush is already in progress&lt;/li&gt;</span>
-<span class="source-line-no">2461</span><span id="line-2461">   * &lt;li&gt;writes are disabled&lt;/li&gt;</span>
-<span class="source-line-no">2462</span><span id="line-2462">   * &lt;/ol&gt;</span>
-<span class="source-line-no">2463</span><span id="line-2463">   * &lt;p&gt;</span>
-<span class="source-line-no">2464</span><span id="line-2464">   * This method may block for some time, so it should not be called from a time-sensitive thread.</span>
-<span class="source-line-no">2465</span><span id="line-2465">   * @param flushAllStores whether we want to force a flush of all stores</span>
-<span class="source-line-no">2466</span><span id="line-2466">   * @return FlushResult indicating whether the flush was successful or not and if the region needs</span>
-<span class="source-line-no">2467</span><span id="line-2467">   *         compacting</span>
-<span class="source-line-no">2468</span><span id="line-2468">   * @throws IOException general io exceptions because a snapshot was not properly persisted.</span>
-<span class="source-line-no">2469</span><span id="line-2469">   */</span>
-<span class="source-line-no">2470</span><span id="line-2470">  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs</span>
-<span class="source-line-no">2471</span><span id="line-2471">  public FlushResult flush(boolean flushAllStores) throws IOException {</span>
-<span class="source-line-no">2472</span><span id="line-2472">    return flushcache(flushAllStores, false, FlushLifeCycleTracker.DUMMY);</span>
-<span class="source-line-no">2473</span><span id="line-2473">  }</span>
-<span class="source-line-no">2474</span><span id="line-2474"></span>
-<span class="source-line-no">2475</span><span id="line-2475">  public interface FlushResult {</span>
-<span class="source-line-no">2476</span><span id="line-2476">    enum Result {</span>
-<span class="source-line-no">2477</span><span id="line-2477">      FLUSHED_NO_COMPACTION_NEEDED,</span>
-<span class="source-line-no">2478</span><span id="line-2478">      FLUSHED_COMPACTION_NEEDED,</span>
-<span class="source-line-no">2479</span><span id="line-2479">      // Special case where a flush didn't run because there's nothing in the memstores. Used when</span>
-<span class="source-line-no">2480</span><span id="line-2480">      // bulk loading to know when we can still load even if a flush didn't happen.</span>
-<span class="source-line-no">2481</span><span id="line-2481">      CANNOT_FLUSH_MEMSTORE_EMPTY,</span>
-<span class="source-line-no">2482</span><span id="line-2482">      CANNOT_FLUSH</span>
-<span class="source-line-no">2483</span><span id="line-2483">    }</span>
-<span class="source-line-no">2484</span><span id="line-2484"></span>
-<span class="source-line-no">2485</span><span id="line-2485">    /** Returns the detailed result code */</span>
-<span class="source-line-no">2486</span><span id="line-2486">    Result getResult();</span>
-<span class="source-line-no">2487</span><span id="line-2487"></span>
-<span class="source-line-no">2488</span><span id="line-2488">    /** Returns true if the memstores were flushed, else false */</span>
-<span class="source-line-no">2489</span><span id="line-2489">    boolean isFlushSucceeded();</span>
-<span class="source-line-no">2490</span><span id="line-2490"></span>
-<span class="source-line-no">2491</span><span id="line-2491">    /** Returns True if the flush requested a compaction, else false */</span>
-<span class="source-line-no">2492</span><span id="line-2492">    boolean isCompactionNeeded();</span>
-<span class="source-line-no">2493</span><span id="line-2493">  }</span>
-<span class="source-line-no">2494</span><span id="line-2494"></span>
-<span class="source-line-no">2495</span><span id="line-2495">  public FlushResultImpl flushcache(boolean flushAllStores, boolean writeFlushRequestWalMarker,</span>
-<span class="source-line-no">2496</span><span id="line-2496">    FlushLifeCycleTracker tracker) throws IOException {</span>
-<span class="source-line-no">2497</span><span id="line-2497">    List&lt;byte[]&gt; families = null;</span>
-<span class="source-line-no">2498</span><span id="line-2498">    if (flushAllStores) {</span>
-<span class="source-line-no">2499</span><span id="line-2499">      families = new ArrayList&lt;&gt;();</span>
-<span class="source-line-no">2500</span><span id="line-2500">      families.addAll(this.getTableDescriptor().getColumnFamilyNames());</span>
-<span class="source-line-no">2501</span><span id="line-2501">    }</span>
-<span class="source-line-no">2502</span><span id="line-2502">    return this.flushcache(families, writeFlushRequestWalMarker, tracker);</span>
-<span class="source-line-no">2503</span><span id="line-2503">  }</span>
-<span class="source-line-no">2504</span><span id="line-2504"></span>
-<span class="source-line-no">2505</span><span id="line-2505">  /**</span>
-<span class="source-line-no">2506</span><span id="line-2506">   * Flush the cache. When this method is called the cache will be flushed unless:</span>
-<span class="source-line-no">2507</span><span id="line-2507">   * &lt;ol&gt;</span>
-<span class="source-line-no">2508</span><span id="line-2508">   * &lt;li&gt;the cache is empty&lt;/li&gt;</span>
-<span class="source-line-no">2509</span><span id="line-2509">   * &lt;li&gt;the region is closed.&lt;/li&gt;</span>
-<span class="source-line-no">2510</span><span id="line-2510">   * &lt;li&gt;a flush is already in progress&lt;/li&gt;</span>
-<span class="source-line-no">2511</span><span id="line-2511">   * &lt;li&gt;writes are disabled&lt;/li&gt;</span>
-<span class="source-line-no">2512</span><span id="line-2512">   * &lt;/ol&gt;</span>
-<span class="source-line-no">2513</span><span id="line-2513">   * &lt;p&gt;</span>
-<span class="source-line-no">2514</span><span id="line-2514">   * This method may block for some time, so it should not be called from a time-sensitive thread.</span>
-<span class="source-line-no">2515</span><span id="line-2515">   * @param families                   stores of region to flush.</span>
-<span class="source-line-no">2516</span><span id="line-2516">   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL</span>
-<span class="source-line-no">2517</span><span id="line-2517">   * @param tracker                    used to track the life cycle of this flush</span>
-<span class="source-line-no">2518</span><span id="line-2518">   * @return whether the flush is success and whether the region needs compacting</span>
-<span class="source-line-no">2519</span><span id="line-2519">   * @throws IOException              general io exceptions</span>
-<span class="source-line-no">2520</span><span id="line-2520">   * @throws DroppedSnapshotException Thrown when replay of wal is required because a Snapshot was</span>
-<span class="source-line-no">2521</span><span id="line-2521">   *                                  not properly persisted. The region is put in closing mode, and</span>
-<span class="source-line-no">2522</span><span id="line-2522">   *                                  the caller MUST abort after this.</span>
-<span class="source-line-no">2523</span><span id="line-2523">   */</span>
-<span class="source-line-no">2524</span><span id="line-2524">  public FlushResultImpl flushcache(List&lt;byte[]&gt; families, boolean writeFlushRequestWalMarker,</span>
-<span class="source-line-no">2525</span><span id="line-2525">    FlushLifeCycleTracker tracker) throws IOException {</span>
-<span class="source-line-no">2526</span><span id="line-2526">    // fail-fast instead of waiting on the lock</span>
-<span class="source-line-no">2527</span><span id="line-2527">    if (this.closing.get()) {</span>
-<span class="source-line-no">2528</span><span id="line-2528">      String msg = "Skipping flush on " + this + " because closing";</span>
-<span class="source-line-no">2529</span><span id="line-2529">      LOG.debug(msg);</span>
-<span class="source-line-no">2530</span><span id="line-2530">      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);</span>
-<span class="source-line-no">2531</span><span id="line-2531">    }</span>
-<span class="source-line-no">2532</span><span id="line-2532">    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);</span>
-<span class="source-line-no">2533</span><span id="line-2533">    status.setStatus("Acquiring readlock on region");</span>
-<span class="source-line-no">2534</span><span id="line-2534">    // block waiting for the lock for flushing cache</span>
-<span class="source-line-no">2535</span><span id="line-2535">    lock.readLock().lock();</span>
-<span class="source-line-no">2536</span><span id="line-2536">    boolean flushed = true;</span>
-<span class="source-line-no">2537</span><span id="line-2537">    try {</span>
-<span class="source-line-no">2538</span><span id="line-2538">      if (this.closed.get()) {</span>
-<span class="source-line-no">2539</span><span id="line-2539">        String msg = "Skipping flush on " + this + " because closed";</span>
-<span class="source-line-no">2540</span><span id="line-2540">        LOG.debug(msg);</span>
-<span class="source-line-no">2541</span><span id="line-2541">        status.abort(msg);</span>
-<span class="source-line-no">2542</span><span id="line-2542">        flushed = false;</span>
-<span class="source-line-no">2543</span><span id="line-2543">        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);</span>
-<span class="source-line-no">2544</span><span id="line-2544">      }</span>
-<span class="source-line-no">2545</span><span id="line-2545">      if (coprocessorHost != null) {</span>
-<span class="source-line-no">2546</span><span id="line-2546">        status.setStatus("Running coprocessor pre-flush hooks");</span>
-<span class="source-line-no">2547</span><span id="line-2547">        coprocessorHost.preFlush(tracker);</span>
-<span class="source-line-no">2548</span><span id="line-2548">      }</span>
-<span class="source-line-no">2549</span><span id="line-2549">      // TODO: this should be managed within memstore with the snapshot, updated only after flush</span>
-<span class="source-line-no">2550</span><span id="line-2550">      // successful</span>
-<span class="source-line-no">2551</span><span id="line-2551">      if (numMutationsWithoutWAL.sum() &gt; 0) {</span>
-<span class="source-line-no">2552</span><span id="line-2552">        numMutationsWithoutWAL.reset();</span>
-<span class="source-line-no">2553</span><span id="line-2553">        dataInMemoryWithoutWAL.reset();</span>
-<span class="source-line-no">2554</span><span id="line-2554">      }</span>
-<span class="source-line-no">2555</span><span id="line-2555">      synchronized (writestate) {</span>
-<span class="source-line-no">2556</span><span id="line-2556">        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {</span>
-<span class="source-line-no">2557</span><span id="line-2557">          this.writestate.flushing = true;</span>
-<span class="source-line-no">2558</span><span id="line-2558">        } else {</span>
-<span class="source-line-no">2559</span><span id="line-2559">          String msg = "NOT flushing " + this + " as "</span>
-<span class="source-line-no">2560</span><span id="line-2560">            + (writestate.flushing ? "already flushing" : "writes are not enabled");</span>
-<span class="source-line-no">2561</span><span id="line-2561">          LOG.debug(msg);</span>
-<span class="source-line-no">2562</span><span id="line-2562">          status.abort(msg);</span>
-<span class="source-line-no">2563</span><span id="line-2563">          flushed = false;</span>
-<span class="source-line-no">2564</span><span id="line-2564">          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);</span>
-<span class="source-line-no">2565</span><span id="line-2565">        }</span>
-<span class="source-line-no">2566</span><span id="line-2566">      }</span>
+<span class="source-line-no">2335</span><span id="line-2335">   * &lt;p&gt;</span>
+<span class="source-line-no">2336</span><span id="line-2336">   * We are trying to remove / relax the region read lock for compaction. Let's see what are the</span>
+<span class="source-line-no">2337</span><span id="line-2337">   * potential race conditions among the operations (user scan, region split, region close and</span>
+<span class="source-line-no">2338</span><span id="line-2338">   * region bulk load).</span>
+<span class="source-line-no">2339</span><span id="line-2339">   * &lt;/p&gt;</span>
+<span class="source-line-no">2340</span><span id="line-2340">   *</span>
+<span class="source-line-no">2341</span><span id="line-2341">   * &lt;pre&gt;</span>
+<span class="source-line-no">2342</span><span id="line-2342">   *   user scan ---&gt; region read lock</span>
+<span class="source-line-no">2343</span><span id="line-2343">   *   region split --&gt; region close first --&gt; region write lock</span>
+<span class="source-line-no">2344</span><span id="line-2344">   *   region close --&gt; region write lock</span>
+<span class="source-line-no">2345</span><span id="line-2345">   *   region bulk load --&gt; region write lock</span>
+<span class="source-line-no">2346</span><span id="line-2346">   * &lt;/pre&gt;</span>
+<span class="source-line-no">2347</span><span id="line-2347">   * &lt;p&gt;</span>
+<span class="source-line-no">2348</span><span id="line-2348">   * read lock is compatible with read lock. ---&gt; no problem with user scan/read region bulk load</span>
+<span class="source-line-no">2349</span><span id="line-2349">   * does not cause problem for compaction (no consistency problem, store lock will help the store</span>
+<span class="source-line-no">2350</span><span id="line-2350">   * file accounting). They can run almost concurrently at the region level.</span>
+<span class="source-line-no">2351</span><span id="line-2351">   * &lt;/p&gt;</span>
+<span class="source-line-no">2352</span><span id="line-2352">   * &lt;p&gt;</span>
+<span class="source-line-no">2353</span><span id="line-2353">   * The only remaining race condition is between the region close and compaction. So we will</span>
+<span class="source-line-no">2354</span><span id="line-2354">   * evaluate, below, how region close intervenes with compaction if compaction does not acquire</span>
+<span class="source-line-no">2355</span><span id="line-2355">   * region read lock.</span>
+<span class="source-line-no">2356</span><span id="line-2356">   * &lt;/p&gt;</span>
+<span class="source-line-no">2357</span><span id="line-2357">   * &lt;p&gt;</span>
+<span class="source-line-no">2358</span><span id="line-2358">   * Here are the steps for compaction:</span>
+<span class="source-line-no">2359</span><span id="line-2359">   * &lt;ol&gt;</span>
+<span class="source-line-no">2360</span><span id="line-2360">   * &lt;li&gt;obtain list of StoreFile's&lt;/li&gt;</span>
+<span class="source-line-no">2361</span><span id="line-2361">   * &lt;li&gt;create StoreFileScanner's based on list from #1&lt;/li&gt;</span>
+<span class="source-line-no">2362</span><span id="line-2362">   * &lt;li&gt;perform compaction and save resulting files under tmp dir&lt;/li&gt;</span>
+<span class="source-line-no">2363</span><span id="line-2363">   * &lt;li&gt;swap in compacted files&lt;/li&gt;</span>
+<span class="source-line-no">2364</span><span id="line-2364">   * &lt;/ol&gt;</span>
+<span class="source-line-no">2365</span><span id="line-2365">   * &lt;/p&gt;</span>
+<span class="source-line-no">2366</span><span id="line-2366">   * &lt;p&gt;</span>
+<span class="source-line-no">2367</span><span id="line-2367">   * #1 is guarded by store lock. This patch does not change this --&gt; no worse or better For #2, we</span>
+<span class="source-line-no">2368</span><span id="line-2368">   * obtain smallest read point (for region) across all the Scanners (for both default compactor and</span>
+<span class="source-line-no">2369</span><span id="line-2369">   * stripe compactor). The read points are for user scans. Region keeps the read points for all</span>
+<span class="source-line-no">2370</span><span id="line-2370">   * currently open user scanners. Compaction needs to know the smallest read point so that during</span>
+<span class="source-line-no">2371</span><span id="line-2371">   * re-write of the hfiles, it can remove the mvcc points for the cells if their mvccs are older</span>
+<span class="source-line-no">2372</span><span id="line-2372">   * than the smallest since they are not needed anymore. This will not conflict with compaction.</span>
+<span class="source-line-no">2373</span><span id="line-2373">   * &lt;/p&gt;</span>
+<span class="source-line-no">2374</span><span id="line-2374">   * &lt;p&gt;</span>
+<span class="source-line-no">2375</span><span id="line-2375">   * For #3, it can be performed in parallel to other operations.</span>
+<span class="source-line-no">2376</span><span id="line-2376">   * &lt;/p&gt;</span>
+<span class="source-line-no">2377</span><span id="line-2377">   * &lt;p&gt;</span>
+<span class="source-line-no">2378</span><span id="line-2378">   * For #4 bulk load and compaction don't conflict with each other on the region level (for</span>
+<span class="source-line-no">2379</span><span id="line-2379">   * multi-family atomicy).</span>
+<span class="source-line-no">2380</span><span id="line-2380">   * &lt;/p&gt;</span>
+<span class="source-line-no">2381</span><span id="line-2381">   * &lt;p&gt;</span>
+<span class="source-line-no">2382</span><span id="line-2382">   * Region close and compaction are guarded pretty well by the 'writestate'. In HRegion#doClose(),</span>
+<span class="source-line-no">2383</span><span id="line-2383">   * we have :</span>
+<span class="source-line-no">2384</span><span id="line-2384">   *</span>
+<span class="source-line-no">2385</span><span id="line-2385">   * &lt;pre&gt;</span>
+<span class="source-line-no">2386</span><span id="line-2386">   * synchronized (writestate) {</span>
+<span class="source-line-no">2387</span><span id="line-2387">   *   // Disable compacting and flushing by background threads for this</span>
+<span class="source-line-no">2388</span><span id="line-2388">   *   // region.</span>
+<span class="source-line-no">2389</span><span id="line-2389">   *   canFlush = !writestate.readOnly;</span>
+<span class="source-line-no">2390</span><span id="line-2390">   *   writestate.writesEnabled = false;</span>
+<span class="source-line-no">2391</span><span id="line-2391">   *   LOG.debug("Closing " + this + ": disabling compactions &amp; flushes");</span>
+<span class="source-line-no">2392</span><span id="line-2392">   *   waitForFlushesAndCompactions();</span>
+<span class="source-line-no">2393</span><span id="line-2393">   * }</span>
+<span class="source-line-no">2394</span><span id="line-2394">   * &lt;/pre&gt;</span>
+<span class="source-line-no">2395</span><span id="line-2395">   *</span>
+<span class="source-line-no">2396</span><span id="line-2396">   * {@code waitForFlushesAndCompactions()} would wait for {@code writestate.compacting} to come</span>
+<span class="source-line-no">2397</span><span id="line-2397">   * down to 0. and in {@code HRegion.compact()}</span>
+<span class="source-line-no">2398</span><span id="line-2398">   *</span>
+<span class="source-line-no">2399</span><span id="line-2399">   * &lt;pre&gt;</span>
+<span class="source-line-no">2400</span><span id="line-2400">   *   try {</span>
+<span class="source-line-no">2401</span><span id="line-2401">   *     synchronized (writestate) {</span>
+<span class="source-line-no">2402</span><span id="line-2402">   *       if (writestate.writesEnabled) {</span>
+<span class="source-line-no">2403</span><span id="line-2403">   *         wasStateSet = true;</span>
+<span class="source-line-no">2404</span><span id="line-2404">   *         ++writestate.compacting;</span>
+<span class="source-line-no">2405</span><span id="line-2405">   *       } else {</span>
+<span class="source-line-no">2406</span><span id="line-2406">   *         String msg = "NOT compacting region " + this + ". Writes disabled.";</span>
+<span class="source-line-no">2407</span><span id="line-2407">   *         LOG.info(msg);</span>
+<span class="source-line-no">2408</span><span id="line-2408">   *         status.abort(msg);</span>
+<span class="source-line-no">2409</span><span id="line-2409">   *         return false;</span>
+<span class="source-line-no">2410</span><span id="line-2410">   *       }</span>
+<span class="source-line-no">2411</span><span id="line-2411">   *     }</span>
+<span class="source-line-no">2412</span><span id="line-2412">   *   }</span>
+<span class="source-line-no">2413</span><span id="line-2413">   * &lt;/pre&gt;</span>
+<span class="source-line-no">2414</span><span id="line-2414">   *</span>
+<span class="source-line-no">2415</span><span id="line-2415">   * Also in {@code compactor.performCompaction()}: check periodically to see if a system stop is</span>
+<span class="source-line-no">2416</span><span id="line-2416">   * requested</span>
+<span class="source-line-no">2417</span><span id="line-2417">   *</span>
+<span class="source-line-no">2418</span><span id="line-2418">   * &lt;pre&gt;</span>
+<span class="source-line-no">2419</span><span id="line-2419">   * if (closeChecker != null &amp;&amp; closeChecker.isTimeLimit(store, now)) {</span>
+<span class="source-line-no">2420</span><span id="line-2420">   *   progress.cancel();</span>
+<span class="source-line-no">2421</span><span id="line-2421">   *   return false;</span>
+<span class="source-line-no">2422</span><span id="line-2422">   * }</span>
+<span class="source-line-no">2423</span><span id="line-2423">   * if (closeChecker != null &amp;&amp; closeChecker.isSizeLimit(store, len)) {</span>
+<span class="source-line-no">2424</span><span id="line-2424">   *   progress.cancel();</span>
+<span class="source-line-no">2425</span><span id="line-2425">   *   return false;</span>
+<span class="source-line-no">2426</span><span id="line-2426">   * }</span>
+<span class="source-line-no">2427</span><span id="line-2427">   * &lt;/pre&gt;</span>
+<span class="source-line-no">2428</span><span id="line-2428">   * &lt;/p&gt;</span>
+<span class="source-line-no">2429</span><span id="line-2429">   */</span>
+<span class="source-line-no">2430</span><span id="line-2430">  public boolean compact(CompactionContext compaction, HStore store,</span>
+<span class="source-line-no">2431</span><span id="line-2431">    ThroughputController throughputController, User user) throws IOException {</span>
+<span class="source-line-no">2432</span><span id="line-2432">    assert compaction != null &amp;&amp; compaction.hasSelection();</span>
+<span class="source-line-no">2433</span><span id="line-2433">    assert !compaction.getRequest().getFiles().isEmpty();</span>
+<span class="source-line-no">2434</span><span id="line-2434">    if (this.closing.get() || this.closed.get()) {</span>
+<span class="source-line-no">2435</span><span id="line-2435">      LOG.debug("Skipping compaction on " + this + " because closing/closed");</span>
+<span class="source-line-no">2436</span><span id="line-2436">      store.cancelRequestedCompaction(compaction);</span>
+<span class="source-line-no">2437</span><span id="line-2437">      return false;</span>
+<span class="source-line-no">2438</span><span id="line-2438">    }</span>
+<span class="source-line-no">2439</span><span id="line-2439"></span>
+<span class="source-line-no">2440</span><span id="line-2440">    if (compaction.getRequest().isAllFiles() &amp;&amp; shouldForbidMajorCompaction()) {</span>
+<span class="source-line-no">2441</span><span id="line-2441">      LOG.warn("Skipping major compaction on " + this</span>
+<span class="source-line-no">2442</span><span id="line-2442">        + " because this cluster is transiting sync replication state"</span>
+<span class="source-line-no">2443</span><span id="line-2443">        + " from STANDBY to DOWNGRADE_ACTIVE");</span>
+<span class="source-line-no">2444</span><span id="line-2444">      store.cancelRequestedCompaction(compaction);</span>
+<span class="source-line-no">2445</span><span id="line-2445">      return false;</span>
+<span class="source-line-no">2446</span><span id="line-2446">    }</span>
+<span class="source-line-no">2447</span><span id="line-2447"></span>
+<span class="source-line-no">2448</span><span id="line-2448">    MonitoredTask status = null;</span>
+<span class="source-line-no">2449</span><span id="line-2449">    boolean requestNeedsCancellation = true;</span>
+<span class="source-line-no">2450</span><span id="line-2450">    try {</span>
+<span class="source-line-no">2451</span><span id="line-2451">      byte[] cf = Bytes.toBytes(store.getColumnFamilyName());</span>
+<span class="source-line-no">2452</span><span id="line-2452">      if (stores.get(cf) != store) {</span>
+<span class="source-line-no">2453</span><span id="line-2453">        LOG.warn("Store " + store.getColumnFamilyName() + " on region " + this</span>
+<span class="source-line-no">2454</span><span id="line-2454">          + " has been re-instantiated, cancel this compaction request. "</span>
+<span class="source-line-no">2455</span><span id="line-2455">          + " It may be caused by the roll back of split transaction");</span>
+<span class="source-line-no">2456</span><span id="line-2456">        return false;</span>
+<span class="source-line-no">2457</span><span id="line-2457">      }</span>
+<span class="source-line-no">2458</span><span id="line-2458"></span>
+<span class="source-line-no">2459</span><span id="line-2459">      status = TaskMonitor.get().createStatus("Compacting " + store + " in " + this);</span>
+<span class="source-line-no">2460</span><span id="line-2460">      if (this.closed.get()) {</span>
+<span class="source-line-no">2461</span><span id="line-2461">        String msg = "Skipping compaction on " + this + " because closed";</span>
+<span class="source-line-no">2462</span><span id="line-2462">        LOG.debug(msg);</span>
+<span class="source-line-no">2463</span><span id="line-2463">        status.abort(msg);</span>
+<span class="source-line-no">2464</span><span id="line-2464">        return false;</span>
+<span class="source-line-no">2465</span><span id="line-2465">      }</span>
+<span class="source-line-no">2466</span><span id="line-2466">      boolean wasStateSet = false;</span>
+<span class="source-line-no">2467</span><span id="line-2467">      try {</span>
+<span class="source-line-no">2468</span><span id="line-2468">        synchronized (writestate) {</span>
+<span class="source-line-no">2469</span><span id="line-2469">          if (writestate.writesEnabled) {</span>
+<span class="source-line-no">2470</span><span id="line-2470">            wasStateSet = true;</span>
+<span class="source-line-no">2471</span><span id="line-2471">            writestate.compacting.incrementAndGet();</span>
+<span class="source-line-no">2472</span><span id="line-2472">          } else {</span>
+<span class="source-line-no">2473</span><span id="line-2473">            String msg = "NOT compacting region " + this + ". Writes disabled.";</span>
+<span class="source-line-no">2474</span><span id="line-2474">            LOG.info(msg);</span>
+<span class="source-line-no">2475</span><span id="line-2475">            status.abort(msg);</span>
+<span class="source-line-no">2476</span><span id="line-2476">            return false;</span>
+<span class="source-line-no">2477</span><span id="line-2477">          }</span>
+<span class="source-line-no">2478</span><span id="line-2478">        }</span>
+<span class="source-line-no">2479</span><span id="line-2479">        LOG.info("Starting compaction of {} in {}{}", store, this,</span>
+<span class="source-line-no">2480</span><span id="line-2480">          (compaction.getRequest().isOffPeak() ? " as an off-peak compaction" : ""));</span>
+<span class="source-line-no">2481</span><span id="line-2481">        doRegionCompactionPrep();</span>
+<span class="source-line-no">2482</span><span id="line-2482">        try {</span>
+<span class="source-line-no">2483</span><span id="line-2483">          status.setStatus("Compacting store " + store);</span>
+<span class="source-line-no">2484</span><span id="line-2484">          // We no longer need to cancel the request on the way out of this</span>
+<span class="source-line-no">2485</span><span id="line-2485">          // method because Store#compact will clean up unconditionally</span>
+<span class="source-line-no">2486</span><span id="line-2486">          requestNeedsCancellation = false;</span>
+<span class="source-line-no">2487</span><span id="line-2487">          store.compact(compaction, throughputController, user);</span>
+<span class="source-line-no">2488</span><span id="line-2488">        } catch (InterruptedIOException iioe) {</span>
+<span class="source-line-no">2489</span><span id="line-2489">          String msg = "region " + this + " compaction interrupted";</span>
+<span class="source-line-no">2490</span><span id="line-2490">          LOG.info(msg, iioe);</span>
+<span class="source-line-no">2491</span><span id="line-2491">          status.abort(msg);</span>
+<span class="source-line-no">2492</span><span id="line-2492">          return false;</span>
+<span class="source-line-no">2493</span><span id="line-2493">        }</span>
+<span class="source-line-no">2494</span><span id="line-2494">      } finally {</span>
+<span class="source-line-no">2495</span><span id="line-2495">        if (wasStateSet) {</span>
+<span class="source-line-no">2496</span><span id="line-2496">          synchronized (writestate) {</span>
+<span class="source-line-no">2497</span><span id="line-2497">            writestate.compacting.decrementAndGet();</span>
+<span class="source-line-no">2498</span><span id="line-2498">            if (writestate.compacting.get() &lt;= 0) {</span>
+<span class="source-line-no">2499</span><span id="line-2499">              writestate.notifyAll();</span>
+<span class="source-line-no">2500</span><span id="line-2500">            }</span>
+<span class="source-line-no">2501</span><span id="line-2501">          }</span>
+<span class="source-line-no">2502</span><span id="line-2502">        }</span>
+<span class="source-line-no">2503</span><span id="line-2503">      }</span>
+<span class="source-line-no">2504</span><span id="line-2504">      status.markComplete("Compaction complete");</span>
+<span class="source-line-no">2505</span><span id="line-2505">      return true;</span>
+<span class="source-line-no">2506</span><span id="line-2506">    } finally {</span>
+<span class="source-line-no">2507</span><span id="line-2507">      if (requestNeedsCancellation) store.cancelRequestedCompaction(compaction);</span>
+<span class="source-line-no">2508</span><span id="line-2508">      if (status != null) {</span>
+<span class="source-line-no">2509</span><span id="line-2509">        LOG.debug("Compaction status journal for {}:\n{}", this.getRegionInfo().getEncodedName(),</span>
+<span class="source-line-no">2510</span><span id="line-2510">          status.prettyPrintJournal());</span>
+<span class="source-line-no">2511</span><span id="line-2511">        status.cleanup();</span>
+<span class="source-line-no">2512</span><span id="line-2512">      }</span>
+<span class="source-line-no">2513</span><span id="line-2513">    }</span>
+<span class="source-line-no">2514</span><span id="line-2514">  }</span>
+<span class="source-line-no">2515</span><span id="line-2515"></span>
+<span class="source-line-no">2516</span><span id="line-2516">  /**</span>
+<span class="source-line-no">2517</span><span id="line-2517">   * Flush the cache.</span>
+<span class="source-line-no">2518</span><span id="line-2518">   * &lt;p&gt;</span>
+<span class="source-line-no">2519</span><span id="line-2519">   * When this method is called the cache will be flushed unless:</span>
+<span class="source-line-no">2520</span><span id="line-2520">   * &lt;ol&gt;</span>
+<span class="source-line-no">2521</span><span id="line-2521">   * &lt;li&gt;the cache is empty&lt;/li&gt;</span>
+<span class="source-line-no">2522</span><span id="line-2522">   * &lt;li&gt;the region is closed.&lt;/li&gt;</span>
+<span class="source-line-no">2523</span><span id="line-2523">   * &lt;li&gt;a flush is already in progress&lt;/li&gt;</span>
+<span class="source-line-no">2524</span><span id="line-2524">   * &lt;li&gt;writes are disabled&lt;/li&gt;</span>
+<span class="source-line-no">2525</span><span id="line-2525">   * &lt;/ol&gt;</span>
+<span class="source-line-no">2526</span><span id="line-2526">   * &lt;p&gt;</span>
+<span class="source-line-no">2527</span><span id="line-2527">   * This method may block for some time, so it should not be called from a time-sensitive thread.</span>
+<span class="source-line-no">2528</span><span id="line-2528">   * @param flushAllStores whether we want to force a flush of all stores</span>
+<span class="source-line-no">2529</span><span id="line-2529">   * @return FlushResult indicating whether the flush was successful or not and if the region needs</span>
+<span class="source-line-no">2530</span><span id="line-2530">   *         compacting</span>
+<span class="source-line-no">2531</span><span id="line-2531">   * @throws IOException general io exceptions because a snapshot was not properly persisted.</span>
+<span class="source-line-no">2532</span><span id="line-2532">   */</span>
+<span class="source-line-no">2533</span><span id="line-2533">  // TODO HBASE-18905. We might have to expose a requestFlush API for CPs</span>
+<span class="source-line-no">2534</span><span id="line-2534">  public FlushResult flush(boolean flushAllStores) throws IOException {</span>
+<span class="source-line-no">2535</span><span id="line-2535">    return flushcache(flushAllStores, false, FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">2536</span><span id="line-2536">  }</span>
+<span class="source-line-no">2537</span><span id="line-2537"></span>
+<span class="source-line-no">2538</span><span id="line-2538">  public interface FlushResult {</span>
+<span class="source-line-no">2539</span><span id="line-2539">    enum Result {</span>
+<span class="source-line-no">2540</span><span id="line-2540">      FLUSHED_NO_COMPACTION_NEEDED,</span>
+<span class="source-line-no">2541</span><span id="line-2541">      FLUSHED_COMPACTION_NEEDED,</span>
+<span class="source-line-no">2542</span><span id="line-2542">      // Special case where a flush didn't run because there's nothing in the memstores. Used when</span>
+<span class="source-line-no">2543</span><span id="line-2543">      // bulk loading to know when we can still load even if a flush didn't happen.</span>
+<span class="source-line-no">2544</span><span id="line-2544">      CANNOT_FLUSH_MEMSTORE_EMPTY,</span>
+<span class="source-line-no">2545</span><span id="line-2545">      CANNOT_FLUSH</span>
+<span class="source-line-no">2546</span><span id="line-2546">    }</span>
+<span class="source-line-no">2547</span><span id="line-2547"></span>
+<span class="source-line-no">2548</span><span id="line-2548">    /** Returns the detailed result code */</span>
+<span class="source-line-no">2549</span><span id="line-2549">    Result getResult();</span>
+<span class="source-line-no">2550</span><span id="line-2550"></span>
+<span class="source-line-no">2551</span><span id="line-2551">    /** Returns true if the memstores were flushed, else false */</span>
+<span class="source-line-no">2552</span><span id="line-2552">    boolean isFlushSucceeded();</span>
+<span class="source-line-no">2553</span><span id="line-2553"></span>
+<span class="source-line-no">2554</span><span id="line-2554">    /** Returns True if the flush requested a compaction, else false */</span>
+<span class="source-line-no">2555</span><span id="line-2555">    boolean isCompactionNeeded();</span>
+<span class="source-line-no">2556</span><span id="line-2556">  }</span>
+<span class="source-line-no">2557</span><span id="line-2557"></span>
+<span class="source-line-no">2558</span><span id="line-2558">  public FlushResultImpl flushcache(boolean flushAllStores, boolean writeFlushRequestWalMarker,</span>
+<span class="source-line-no">2559</span><span id="line-2559">    FlushLifeCycleTracker tracker) throws IOException {</span>
+<span class="source-line-no">2560</span><span id="line-2560">    List&lt;byte[]&gt; families = null;</span>
+<span class="source-line-no">2561</span><span id="line-2561">    if (flushAllStores) {</span>
+<span class="source-line-no">2562</span><span id="line-2562">      families = new ArrayList&lt;&gt;();</span>
+<span class="source-line-no">2563</span><span id="line-2563">      families.addAll(this.getTableDescriptor().getColumnFamilyNames());</span>
+<span class="source-line-no">2564</span><span id="line-2564">    }</span>
+<span class="source-line-no">2565</span><span id="line-2565">    return this.flushcache(families, writeFlushRequestWalMarker, tracker);</span>
+<span class="source-line-no">2566</span><span id="line-2566">  }</span>
 <span class="source-line-no">2567</span><span id="line-2567"></span>
-<span class="source-line-no">2568</span><span id="line-2568">      try {</span>
-<span class="source-line-no">2569</span><span id="line-2569">        // The reason that we do not always use flushPolicy is, when the flush is</span>
-<span class="source-line-no">2570</span><span id="line-2570">        // caused by logRoller, we should select stores which must be flushed</span>
-<span class="source-line-no">2571</span><span id="line-2571">        // rather than could be flushed.</span>
-<span class="source-line-no">2572</span><span id="line-2572">        Collection&lt;HStore&gt; specificStoresToFlush = null;</span>
-<span class="source-line-no">2573</span><span id="line-2573">        if (families != null) {</span>
-<span class="source-line-no">2574</span><span id="line-2574">          specificStoresToFlush = getSpecificStores(families);</span>
-<span class="source-line-no">2575</span><span id="line-2575">        } else {</span>
-<span class="source-line-no">2576</span><span id="line-2576">          specificStoresToFlush = flushPolicy.selectStoresToFlush();</span>
-<span class="source-line-no">2577</span><span id="line-2577">        }</span>
-<span class="source-line-no">2578</span><span id="line-2578">        FlushResultImpl fs =</span>
-<span class="source-line-no">2579</span><span id="line-2579">          internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);</span>
-<span class="source-line-no">2580</span><span id="line-2580"></span>
-<span class="source-line-no">2581</span><span id="line-2581">        if (coprocessorHost != null) {</span>
-<span class="source-line-no">2582</span><span id="line-2582">          status.setStatus("Running post-flush coprocessor hooks");</span>
-<span class="source-line-no">2583</span><span id="line-2583">          coprocessorHost.postFlush(tracker);</span>
-<span class="source-line-no">2584</span><span id="line-2584">        }</span>
-<span class="source-line-no">2585</span><span id="line-2585"></span>
-<span class="source-line-no">2586</span><span id="line-2586">        if (fs.isFlushSucceeded()) {</span>
-<span class="source-line-no">2587</span><span id="line-2587">          flushesQueued.reset();</span>
-<span class="source-line-no">2588</span><span id="line-2588">        }</span>
-<span class="source-line-no">2589</span><span id="line-2589"></span>
-<span class="source-line-no">2590</span><span id="line-2590">        status.markComplete("Flush successful " + fs.toString());</span>
-<span class="source-line-no">2591</span><span id="line-2591">        return fs;</span>
-<span class="source-line-no">2592</span><span id="line-2592">      } finally {</span>
-<span class="source-line-no">2593</span><span id="line-2593">        synchronized (writestate) {</span>
-<span class="source-line-no">2594</span><span id="line-2594">          writestate.flushing = false;</span>
-<span class="source-line-no">2595</span><span id="line-2595">          this.writestate.flushRequested = false;</span>
-<span class="source-line-no">2596</span><span id="line-2596">          writestate.notifyAll();</span>
-<span class="source-line-no">2597</span><span id="line-2597">        }</span>
-<span class="source-line-no">2598</span><span id="line-2598">      }</span>
-<span class="source-line-no">2599</span><span id="line-2599">    } finally {</span>
-<span class="source-line-no">2600</span><span id="line-2600">      lock.readLock().unlock();</span>
-<span class="source-line-no">2601</span><span id="line-2601">      if (flushed) {</span>
-<span class="source-line-no">2602</span><span id="line-2602">        // Don't log this journal stuff if no flush -- confusing.</span>
-<span class="source-line-no">2603</span><span id="line-2603">        LOG.debug("Flush status journal for {}:\n{}", this.getRegionInfo().getEncodedName(),</span>
-<span class="source-line-no">2604</span><span id="line-2604">          status.prettyPrintJournal());</span>
-<span class="source-line-no">2605</span><span id="line-2605">      }</span>
-<span class="source-line-no">2606</span><span id="line-2606">      status.cleanup();</span>
-<span class="source-line-no">2607</span><span id="line-2607">    }</span>
-<span class="source-line-no">2608</span><span id="line-2608">  }</span>
-<span class="source-line-no">2609</span><span id="line-2609"></span>
-<span class="source-line-no">2610</span><span id="line-2610">  /**</span>
-<span class="source-line-no">2611</span><span id="line-2611">   * get stores which matches the specified families</span>
-<span class="source-line-no">2612</span><span id="line-2612">   * @return the stores need to be flushed.</span>
-<span class="source-line-no">2613</span><span id="line-2613">   */</span>
-<span class="source-line-no">2614</span><span id="line-2614">  private Collection&lt;HStore&gt; getSpecificStores(List&lt;byte[]&gt; families) {</span>
-<span class="source-line-no">2615</span><span id="line-2615">    Collection&lt;HStore&gt; specificStoresToFlush = new ArrayList&lt;&gt;();</span>
-<span class="source-line-no">2616</span><span id="line-2616">    for (byte[] family : families) {</span>
-<span class="source-line-no">2617</span><span id="line-2617">      specificStoresToFlush.add(stores.get(family));</span>
-<span class="source-line-no">2618</span><span id="line-2618">    }</span>
-<span class="source-line-no">2619</span><span id="line-2619">    return specificStoresToFlush;</span>
-<span class="source-line-no">2620</span><span id="line-2620">  }</span>
-<span class="source-line-no">2621</span><span id="line-2621"></span>
-<span class="source-line-no">2622</span><span id="line-2622">  /**</span>
-<span class="source-line-no">2623</span><span id="line-2623">   * Should the store be flushed because it is old enough.</span>
-<span class="source-line-no">2624</span><span id="line-2624">   * &lt;p&gt;</span>
-<span class="source-line-no">2625</span><span id="line-2625">   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except</span>
-<span class="source-line-no">2626</span><span id="line-2626">   * that you always flush all stores). Otherwise the method will always returns true which will</span>
-<span class="source-line-no">2627</span><span id="line-2627">   * make a lot of flush requests.</span>
-<span class="source-line-no">2628</span><span id="line-2628">   */</span>
-<span class="source-line-no">2629</span><span id="line-2629">  boolean shouldFlushStore(HStore store) {</span>
-<span class="source-line-no">2630</span><span id="line-2630">    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),</span>
-<span class="source-line-no">2631</span><span id="line-2631">      store.getColumnFamilyDescriptor().getName()) - 1;</span>
-<span class="source-line-no">2632</span><span id="line-2632">    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {</span>
-<span class="source-line-no">2633</span><span id="line-2633">      if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">2634</span><span id="line-2634">        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of "</span>
-<span class="source-line-no">2635</span><span id="line-2635">          + getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest</span>
-<span class="source-line-no">2636</span><span id="line-2636">          + " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());</span>
-<span class="source-line-no">2637</span><span id="line-2637">      }</span>
-<span class="source-line-no">2638</span><span id="line-2638">      return true;</span>
-<span class="source-line-no">2639</span><span id="line-2639">    }</span>
-<span class="source-line-no">2640</span><span id="line-2640">    if (this.flushCheckInterval &lt;= 0) {</span>
-<span class="source-line-no">2641</span><span id="line-2641">      return false;</span>
-<span class="source-line-no">2642</span><span id="line-2642">    }</span>
-<span class="source-line-no">2643</span><span id="line-2643">    long now = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">2644</span><span id="line-2644">    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {</span>
-<span class="source-line-no">2645</span><span id="line-2645">      if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">2646</span><span id="line-2646">        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of "</span>
-<span class="source-line-no">2647</span><span id="line-2647">          + getRegionInfo().getEncodedName() + " because time of oldest edit="</span>
-<span class="source-line-no">2648</span><span id="line-2648">          + store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);</span>
-<span class="source-line-no">2649</span><span id="line-2649">      }</span>
-<span class="source-line-no">2650</span><span id="line-2650">      return true;</span>
-<span class="source-line-no">2651</span><span id="line-2651">    }</span>
-<span class="source-line-no">2652</span><span id="line-2652">    return false;</span>
-<span class="source-line-no">2653</span><span id="line-2653">  }</span>
-<span class="source-line-no">2654</span><span id="line-2654"></span>
-<span class="source-line-no">2655</span><span id="line-2655">  /**</span>
-<span class="source-line-no">2656</span><span id="line-2656">   * Should the memstore be flushed now</span>
-<span class="source-line-no">2657</span><span id="line-2657">   */</span>
-<span class="source-line-no">2658</span><span id="line-2658">  boolean shouldFlush(final StringBuilder whyFlush) {</span>
-<span class="source-line-no">2659</span><span id="line-2659">    whyFlush.setLength(0);</span>
-<span class="source-line-no">2660</span><span id="line-2660">    // This is a rough measure.</span>
-<span class="source-line-no">2661</span><span id="line-2661">    if (</span>
-<span class="source-line-no">2662</span><span id="line-2662">      this.maxFlushedSeqId &gt; 0</span>
-<span class="source-line-no">2663</span><span id="line-2663">        &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())</span>
-<span class="source-line-no">2664</span><span id="line-2664">    ) {</span>
-<span class="source-line-no">2665</span><span id="line-2665">      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");</span>
-<span class="source-line-no">2666</span><span id="line-2666">      return true;</span>
-<span class="source-line-no">2667</span><span id="line-2667">    }</span>
-<span class="source-line-no">2668</span><span id="line-2668">    long modifiedFlushCheckInterval = flushCheckInterval;</span>
-<span class="source-line-no">2669</span><span id="line-2669">    if (</span>
-<span class="source-line-no">2670</span><span id="line-2670">      getRegionInfo().getTable().isSystemTable()</span>
-<span class="source-line-no">2671</span><span id="line-2671">        &amp;&amp; getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID</span>
-<span class="source-line-no">2672</span><span id="line-2672">    ) {</span>
-<span class="source-line-no">2673</span><span id="line-2673">      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;</span>
-<span class="source-line-no">2674</span><span id="line-2674">    }</span>
-<span class="source-line-no">2675</span><span id="line-2675">    if (modifiedFlushCheckInterval &lt;= 0) { // disabled</span>
-<span class="source-line-no">2676</span><span id="line-2676">      return false;</span>
-<span class="source-line-no">2677</span><span id="line-2677">    }</span>
-<span class="source-line-no">2678</span><span id="line-2678">    long now = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">2679</span><span id="line-2679">    // if we flushed in the recent past, we don't need to do again now</span>
-<span class="source-line-no">2680</span><span id="line-2680">    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {</span>
-<span class="source-line-no">2681</span><span id="line-2681">      return false;</span>
-<span class="source-line-no">2682</span><span id="line-2682">    }</span>
-<span class="source-line-no">2683</span><span id="line-2683">    // since we didn't flush in the recent past, flush now if certain conditions</span>
-<span class="source-line-no">2684</span><span id="line-2684">    // are met. Return true on first such memstore hit.</span>
-<span class="source-line-no">2685</span><span id="line-2685">    for (HStore s : stores.values()) {</span>
-<span class="source-line-no">2686</span><span id="line-2686">      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {</span>
-<span class="source-line-no">2687</span><span id="line-2687">        // we have an old enough edit in the memstore, flush</span>
-<span class="source-line-no">2688</span><span id="line-2688">        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");</span>
-<span class="source-line-no">2689</span><span id="line-2689">        return true;</span>
-<span class="source-line-no">2690</span><span id="line-2690">      }</span>
-<span class="source-line-no">2691</span><span id="line-2691">    }</span>
-<span class="source-line-no">2692</span><span id="line-2692">    return false;</span>
-<span class="source-line-no">2693</span><span id="line-2693">  }</span>
-<span class="source-line-no">2694</span><span id="line-2694"></span>
-<span class="source-line-no">2695</span><span id="line-2695">  /**</span>
-<span class="source-line-no">2696</span><span id="line-2696">   * Flushing all stores.</span>
-<span class="source-line-no">2697</span><span id="line-2697">   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)</span>
-<span class="source-line-no">2698</span><span id="line-2698">   */</span>
-<span class="source-line-no">2699</span><span id="line-2699">  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {</span>
-<span class="source-line-no">2700</span><span id="line-2700">    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);</span>
-<span class="source-line-no">2701</span><span id="line-2701">  }</span>
-<span class="source-line-no">2702</span><span id="line-2702"></span>
-<span class="source-line-no">2703</span><span id="line-2703">  /**</span>
-<span class="source-line-no">2704</span><span id="line-2704">   * Flushing given stores.</span>
-<span class="source-line-no">2705</span><span id="line-2705">   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)</span>
-<span class="source-line-no">2706</span><span id="line-2706">   */</span>
-<span class="source-line-no">2707</span><span id="line-2707">  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,</span>
-<span class="source-line-no">2708</span><span id="line-2708">    boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {</span>
-<span class="source-line-no">2709</span><span id="line-2709">    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,</span>
-<span class="source-line-no">2710</span><span id="line-2710">      writeFlushWalMarker, tracker);</span>
-<span class="source-line-no">2711</span><span id="line-2711">  }</span>
-<span class="source-line-no">2712</span><span id="line-2712"></span>
-<span class="source-line-no">2713</span><span id="line-2713">  /**</span>
-<span class="source-line-no">2714</span><span id="line-2714">   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the</span>
-<span class="source-line-no">2715</span><span id="line-2715">   * memstore, all of which have also been written to the wal. We need to write those updates in the</span>
-<span class="source-line-no">2716</span><span id="line-2716">   * memstore out to disk, while being able to process reads/writes as much as possible during the</span>
-<span class="source-line-no">2717</span><span id="line-2717">   * flush operation.</span>
-<span class="source-line-no">2718</span><span id="line-2718">   * &lt;p&gt;</span>
-<span class="source-line-no">2719</span><span id="line-2719">   * This method may block for some time. Every time you call it, we up the regions sequence id even</span>
-<span class="source-line-no">2720</span><span id="line-2720">   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit</span>
-<span class="source-line-no">2721</span><span id="line-2721">   * applied to this region. The returned id does not refer to an actual edit. The returned id can</span>
-<span class="source-line-no">2722</span><span id="line-2722">   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result</span>
-<span class="source-line-no">2723</span><span id="line-2723">   * of this flush, etc.</span>
-<span class="source-line-no">2724</span><span id="line-2724">   * @param wal           Null if we're NOT to go via wal.</span>
-<span class="source-line-no">2725</span><span id="line-2725">   * @param myseqid       The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.</span>
-<span class="source-line-no">2726</span><span id="line-2726">   * @param storesToFlush The list of stores to flush.</span>
-<span class="source-line-no">2727</span><span id="line-2727">   * @return object describing the flush's state</span>
-<span class="source-line-no">2728</span><span id="line-2728">   * @throws IOException              general io exceptions</span>
-<span class="source-line-no">2729</span><span id="line-2729">   * @throws DroppedSnapshotException Thrown when replay of WAL is required.</span>
-<span class="source-line-no">2730</span><span id="line-2730">   */</span>
-<span class="source-line-no">2731</span><span id="line-2731">  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,</span>
-<span class="source-line-no">2732</span><span id="line-2732">    Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,</span>
-<span class="source-line-no">2733</span><span id="line-2733">    FlushLifeCycleTracker tracker) throws IOException {</span>
-<span class="source-line-no">2734</span><span id="line-2734">    PrepareFlushResult result =</span>
-<span class="source-line-no">2735</span><span id="line-2735">      internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);</span>
-<span class="source-line-no">2736</span><span id="line-2736">    if (result.result == null) {</span>
-<span class="source-line-no">2737</span><span id="line-2737">      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);</span>
-<span class="source-line-no">2738</span><span id="line-2738">    } else {</span>
-<span class="source-line-no">2739</span><span id="line-2739">      return result.result; // early exit due to failure from prepare stage</span>
+<span class="source-line-no">2568</span><span id="line-2568">  /**</span>
+<span class="source-line-no">2569</span><span id="line-2569">   * Flush the cache. When this method is called the cache will be flushed unless:</span>
+<span class="source-line-no">2570</span><span id="line-2570">   * &lt;ol&gt;</span>
+<span class="source-line-no">2571</span><span id="line-2571">   * &lt;li&gt;the cache is empty&lt;/li&gt;</span>
+<span class="source-line-no">2572</span><span id="line-2572">   * &lt;li&gt;the region is closed.&lt;/li&gt;</span>
+<span class="source-line-no">2573</span><span id="line-2573">   * &lt;li&gt;a flush is already in progress&lt;/li&gt;</span>
+<span class="source-line-no">2574</span><span id="line-2574">   * &lt;li&gt;writes are disabled&lt;/li&gt;</span>
+<span class="source-line-no">2575</span><span id="line-2575">   * &lt;/ol&gt;</span>
+<span class="source-line-no">2576</span><span id="line-2576">   * &lt;p&gt;</span>
+<span class="source-line-no">2577</span><span id="line-2577">   * This method may block for some time, so it should not be called from a time-sensitive thread.</span>
+<span class="source-line-no">2578</span><span id="line-2578">   * @param families                   stores of region to flush.</span>
+<span class="source-line-no">2579</span><span id="line-2579">   * @param writeFlushRequestWalMarker whether to write the flush request marker to WAL</span>
+<span class="source-line-no">2580</span><span id="line-2580">   * @param tracker                    used to track the life cycle of this flush</span>
+<span class="source-line-no">2581</span><span id="line-2581">   * @return whether the flush is success and whether the region needs compacting</span>
+<span class="source-line-no">2582</span><span id="line-2582">   * @throws IOException              general io exceptions</span>
+<span class="source-line-no">2583</span><span id="line-2583">   * @throws DroppedSnapshotException Thrown when replay of wal is required because a Snapshot was</span>
+<span class="source-line-no">2584</span><span id="line-2584">   *                                  not properly persisted. The region is put in closing mode, and</span>
+<span class="source-line-no">2585</span><span id="line-2585">   *                                  the caller MUST abort after this.</span>
+<span class="source-line-no">2586</span><span id="line-2586">   */</span>
+<span class="source-line-no">2587</span><span id="line-2587">  public FlushResultImpl flushcache(List&lt;byte[]&gt; families, boolean writeFlushRequestWalMarker,</span>
+<span class="source-line-no">2588</span><span id="line-2588">    FlushLifeCycleTracker tracker) throws IOException {</span>
+<span class="source-line-no">2589</span><span id="line-2589">    // fail-fast instead of waiting on the lock</span>
+<span class="source-line-no">2590</span><span id="line-2590">    if (this.closing.get()) {</span>
+<span class="source-line-no">2591</span><span id="line-2591">      String msg = "Skipping flush on " + this + " because closing";</span>
+<span class="source-line-no">2592</span><span id="line-2592">      LOG.debug(msg);</span>
+<span class="source-line-no">2593</span><span id="line-2593">      return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);</span>
+<span class="source-line-no">2594</span><span id="line-2594">    }</span>
+<span class="source-line-no">2595</span><span id="line-2595">    MonitoredTask status = TaskMonitor.get().createStatus("Flushing " + this);</span>
+<span class="source-line-no">2596</span><span id="line-2596">    status.setStatus("Acquiring readlock on region");</span>
+<span class="source-line-no">2597</span><span id="line-2597">    // block waiting for the lock for flushing cache</span>
+<span class="source-line-no">2598</span><span id="line-2598">    lock.readLock().lock();</span>
+<span class="source-line-no">2599</span><span id="line-2599">    boolean flushed = true;</span>
+<span class="source-line-no">2600</span><span id="line-2600">    try {</span>
+<span class="source-line-no">2601</span><span id="line-2601">      if (this.closed.get()) {</span>
+<span class="source-line-no">2602</span><span id="line-2602">        String msg = "Skipping flush on " + this + " because closed";</span>
+<span class="source-line-no">2603</span><span id="line-2603">        LOG.debug(msg);</span>
+<span class="source-line-no">2604</span><span id="line-2604">        status.abort(msg);</span>
+<span class="source-line-no">2605</span><span id="line-2605">        flushed = false;</span>
+<span class="source-line-no">2606</span><span id="line-2606">        return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);</span>
+<span class="source-line-no">2607</span><span id="line-2607">      }</span>
+<span class="source-line-no">2608</span><span id="line-2608">      if (coprocessorHost != null) {</span>
+<span class="source-line-no">2609</span><span id="line-2609">        status.setStatus("Running coprocessor pre-flush hooks");</span>
+<span class="source-line-no">2610</span><span id="line-2610">        coprocessorHost.preFlush(tracker);</span>
+<span class="source-line-no">2611</span><span id="line-2611">      }</span>
+<span class="source-line-no">2612</span><span id="line-2612">      // TODO: this should be managed within memstore with the snapshot, updated only after flush</span>
+<span class="source-line-no">2613</span><span id="line-2613">      // successful</span>
+<span class="source-line-no">2614</span><span id="line-2614">      if (numMutationsWithoutWAL.sum() &gt; 0) {</span>
+<span class="source-line-no">2615</span><span id="line-2615">        numMutationsWithoutWAL.reset();</span>
+<span class="source-line-no">2616</span><span id="line-2616">        dataInMemoryWithoutWAL.reset();</span>
+<span class="source-line-no">2617</span><span id="line-2617">      }</span>
+<span class="source-line-no">2618</span><span id="line-2618">      synchronized (writestate) {</span>
+<span class="source-line-no">2619</span><span id="line-2619">        if (!writestate.flushing &amp;&amp; writestate.writesEnabled) {</span>
+<span class="source-line-no">2620</span><span id="line-2620">          this.writestate.flushing = true;</span>
+<span class="source-line-no">2621</span><span id="line-2621">        } else {</span>
+<span class="source-line-no">2622</span><span id="line-2622">          String msg = "NOT flushing " + this + " as "</span>
+<span class="source-line-no">2623</span><span id="line-2623">            + (writestate.flushing ? "already flushing" : "writes are not enabled");</span>
+<span class="source-line-no">2624</span><span id="line-2624">          LOG.debug(msg);</span>
+<span class="source-line-no">2625</span><span id="line-2625">          status.abort(msg);</span>
+<span class="source-line-no">2626</span><span id="line-2626">          flushed = false;</span>
+<span class="source-line-no">2627</span><span id="line-2627">          return new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false);</span>
+<span class="source-line-no">2628</span><span id="line-2628">        }</span>
+<span class="source-line-no">2629</span><span id="line-2629">      }</span>
+<span class="source-line-no">2630</span><span id="line-2630"></span>
+<span class="source-line-no">2631</span><span id="line-2631">      try {</span>
+<span class="source-line-no">2632</span><span id="line-2632">        // The reason that we do not always use flushPolicy is, when the flush is</span>
+<span class="source-line-no">2633</span><span id="line-2633">        // caused by logRoller, we should select stores which must be flushed</span>
+<span class="source-line-no">2634</span><span id="line-2634">        // rather than could be flushed.</span>
+<span class="source-line-no">2635</span><span id="line-2635">        Collection&lt;HStore&gt; specificStoresToFlush = null;</span>
+<span class="source-line-no">2636</span><span id="line-2636">        if (families != null) {</span>
+<span class="source-line-no">2637</span><span id="line-2637">          specificStoresToFlush = getSpecificStores(families);</span>
+<span class="source-line-no">2638</span><span id="line-2638">        } else {</span>
+<span class="source-line-no">2639</span><span id="line-2639">          specificStoresToFlush = flushPolicy.selectStoresToFlush();</span>
+<span class="source-line-no">2640</span><span id="line-2640">        }</span>
+<span class="source-line-no">2641</span><span id="line-2641">        FlushResultImpl fs =</span>
+<span class="source-line-no">2642</span><span id="line-2642">          internalFlushcache(specificStoresToFlush, status, writeFlushRequestWalMarker, tracker);</span>
+<span class="source-line-no">2643</span><span id="line-2643"></span>
+<span class="source-line-no">2644</span><span id="line-2644">        if (coprocessorHost != null) {</span>
+<span class="source-line-no">2645</span><span id="line-2645">          status.setStatus("Running post-flush coprocessor hooks");</span>
+<span class="source-line-no">2646</span><span id="line-2646">          coprocessorHost.postFlush(tracker);</span>
+<span class="source-line-no">2647</span><span id="line-2647">        }</span>
+<span class="source-line-no">2648</span><span id="line-2648"></span>
+<span class="source-line-no">2649</span><span id="line-2649">        if (fs.isFlushSucceeded()) {</span>
+<span class="source-line-no">2650</span><span id="line-2650">          flushesQueued.reset();</span>
+<span class="source-line-no">2651</span><span id="line-2651">        }</span>
+<span class="source-line-no">2652</span><span id="line-2652"></span>
+<span class="source-line-no">2653</span><span id="line-2653">        status.markComplete("Flush successful " + fs.toString());</span>
+<span class="source-line-no">2654</span><span id="line-2654">        return fs;</span>
+<span class="source-line-no">2655</span><span id="line-2655">      } finally {</span>
+<span class="source-line-no">2656</span><span id="line-2656">        synchronized (writestate) {</span>
+<span class="source-line-no">2657</span><span id="line-2657">          writestate.flushing = false;</span>
+<span class="source-line-no">2658</span><span id="line-2658">          this.writestate.flushRequested = false;</span>
+<span class="source-line-no">2659</span><span id="line-2659">          writestate.notifyAll();</span>
+<span class="source-line-no">2660</span><span id="line-2660">        }</span>
+<span class="source-line-no">2661</span><span id="line-2661">      }</span>
+<span class="source-line-no">2662</span><span id="line-2662">    } finally {</span>
+<span class="source-line-no">2663</span><span id="line-2663">      lock.readLock().unlock();</span>
+<span class="source-line-no">2664</span><span id="line-2664">      if (flushed) {</span>
+<span class="source-line-no">2665</span><span id="line-2665">        // Don't log this journal stuff if no flush -- confusing.</span>
+<span class="source-line-no">2666</span><span id="line-2666">        LOG.debug("Flush status journal for {}:\n{}", this.getRegionInfo().getEncodedName(),</span>
+<span class="source-line-no">2667</span><span id="line-2667">          status.prettyPrintJournal());</span>
+<span class="source-line-no">2668</span><span id="line-2668">      }</span>
+<span class="source-line-no">2669</span><span id="line-2669">      status.cleanup();</span>
+<span class="source-line-no">2670</span><span id="line-2670">    }</span>
+<span class="source-line-no">2671</span><span id="line-2671">  }</span>
+<span class="source-line-no">2672</span><span id="line-2672"></span>
+<span class="source-line-no">2673</span><span id="line-2673">  /**</span>
+<span class="source-line-no">2674</span><span id="line-2674">   * get stores which matches the specified families</span>
+<span class="source-line-no">2675</span><span id="line-2675">   * @return the stores need to be flushed.</span>
+<span class="source-line-no">2676</span><span id="line-2676">   */</span>
+<span class="source-line-no">2677</span><span id="line-2677">  private Collection&lt;HStore&gt; getSpecificStores(List&lt;byte[]&gt; families) {</span>
+<span class="source-line-no">2678</span><span id="line-2678">    Collection&lt;HStore&gt; specificStoresToFlush = new ArrayList&lt;&gt;();</span>
+<span class="source-line-no">2679</span><span id="line-2679">    for (byte[] family : families) {</span>
+<span class="source-line-no">2680</span><span id="line-2680">      specificStoresToFlush.add(stores.get(family));</span>
+<span class="source-line-no">2681</span><span id="line-2681">    }</span>
+<span class="source-line-no">2682</span><span id="line-2682">    return specificStoresToFlush;</span>
+<span class="source-line-no">2683</span><span id="line-2683">  }</span>
+<span class="source-line-no">2684</span><span id="line-2684"></span>
+<span class="source-line-no">2685</span><span id="line-2685">  /**</span>
+<span class="source-line-no">2686</span><span id="line-2686">   * Should the store be flushed because it is old enough.</span>
+<span class="source-line-no">2687</span><span id="line-2687">   * &lt;p&gt;</span>
+<span class="source-line-no">2688</span><span id="line-2688">   * Every FlushPolicy should call this to determine whether a store is old enough to flush (except</span>
+<span class="source-line-no">2689</span><span id="line-2689">   * that you always flush all stores). Otherwise the method will always returns true which will</span>
+<span class="source-line-no">2690</span><span id="line-2690">   * make a lot of flush requests.</span>
+<span class="source-line-no">2691</span><span id="line-2691">   */</span>
+<span class="source-line-no">2692</span><span id="line-2692">  boolean shouldFlushStore(HStore store) {</span>
+<span class="source-line-no">2693</span><span id="line-2693">    long earliest = this.wal.getEarliestMemStoreSeqNum(getRegionInfo().getEncodedNameAsBytes(),</span>
+<span class="source-line-no">2694</span><span id="line-2694">      store.getColumnFamilyDescriptor().getName()) - 1;</span>
+<span class="source-line-no">2695</span><span id="line-2695">    if (earliest &gt; 0 &amp;&amp; earliest + flushPerChanges &lt; mvcc.getReadPoint()) {</span>
+<span class="source-line-no">2696</span><span id="line-2696">      if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">2697</span><span id="line-2697">        LOG.debug("Flush column family " + store.getColumnFamilyName() + " of "</span>
+<span class="source-line-no">2698</span><span id="line-2698">          + getRegionInfo().getEncodedName() + " because unflushed sequenceid=" + earliest</span>
+<span class="source-line-no">2699</span><span id="line-2699">          + " is &gt; " + this.flushPerChanges + " from current=" + mvcc.getReadPoint());</span>
+<span class="source-line-no">2700</span><span id="line-2700">      }</span>
+<span class="source-line-no">2701</span><span id="line-2701">      return true;</span>
+<span class="source-line-no">2702</span><span id="line-2702">    }</span>
+<span class="source-line-no">2703</span><span id="line-2703">    if (this.flushCheckInterval &lt;= 0) {</span>
+<span class="source-line-no">2704</span><span id="line-2704">      return false;</span>
+<span class="source-line-no">2705</span><span id="line-2705">    }</span>
+<span class="source-line-no">2706</span><span id="line-2706">    long now = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">2707</span><span id="line-2707">    if (store.timeOfOldestEdit() &lt; now - this.flushCheckInterval) {</span>
+<span class="source-line-no">2708</span><span id="line-2708">      if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">2709</span><span id="line-2709">        LOG.debug("Flush column family: " + store.getColumnFamilyName() + " of "</span>
+<span class="source-line-no">2710</span><span id="line-2710">          + getRegionInfo().getEncodedName() + " because time of oldest edit="</span>
+<span class="source-line-no">2711</span><span id="line-2711">          + store.timeOfOldestEdit() + " is &gt; " + this.flushCheckInterval + " from now =" + now);</span>
+<span class="source-line-no">2712</span><span id="line-2712">      }</span>
+<span class="source-line-no">2713</span><span id="line-2713">      return true;</span>
+<span class="source-line-no">2714</span><span id="line-2714">    }</span>
+<span class="source-line-no">2715</span><span id="line-2715">    return false;</span>
+<span class="source-line-no">2716</span><span id="line-2716">  }</span>
+<span class="source-line-no">2717</span><span id="line-2717"></span>
+<span class="source-line-no">2718</span><span id="line-2718">  /**</span>
+<span class="source-line-no">2719</span><span id="line-2719">   * Should the memstore be flushed now</span>
+<span class="source-line-no">2720</span><span id="line-2720">   */</span>
+<span class="source-line-no">2721</span><span id="line-2721">  boolean shouldFlush(final StringBuilder whyFlush) {</span>
+<span class="source-line-no">2722</span><span id="line-2722">    whyFlush.setLength(0);</span>
+<span class="source-line-no">2723</span><span id="line-2723">    // This is a rough measure.</span>
+<span class="source-line-no">2724</span><span id="line-2724">    if (</span>
+<span class="source-line-no">2725</span><span id="line-2725">      this.maxFlushedSeqId &gt; 0</span>
+<span class="source-line-no">2726</span><span id="line-2726">        &amp;&amp; (this.maxFlushedSeqId + this.flushPerChanges &lt; this.mvcc.getReadPoint())</span>
+<span class="source-line-no">2727</span><span id="line-2727">    ) {</span>
+<span class="source-line-no">2728</span><span id="line-2728">      whyFlush.append("more than max edits, " + this.flushPerChanges + ", since last flush");</span>
+<span class="source-line-no">2729</span><span id="line-2729">      return true;</span>
+<span class="source-line-no">2730</span><span id="line-2730">    }</span>
+<span class="source-line-no">2731</span><span id="line-2731">    long modifiedFlushCheckInterval = flushCheckInterval;</span>
+<span class="source-line-no">2732</span><span id="line-2732">    if (</span>
+<span class="source-line-no">2733</span><span id="line-2733">      getRegionInfo().getTable().isSystemTable()</span>
+<span class="source-line-no">2734</span><span id="line-2734">        &amp;&amp; getRegionInfo().getReplicaId() == RegionInfo.DEFAULT_REPLICA_ID</span>
+<span class="source-line-no">2735</span><span id="line-2735">    ) {</span>
+<span class="source-line-no">2736</span><span id="line-2736">      modifiedFlushCheckInterval = SYSTEM_CACHE_FLUSH_INTERVAL;</span>
+<span class="source-line-no">2737</span><span id="line-2737">    }</span>
+<span class="source-line-no">2738</span><span id="line-2738">    if (modifiedFlushCheckInterval &lt;= 0) { // disabled</span>
+<span class="source-line-no">2739</span><span id="line-2739">      return false;</span>
 <span class="source-line-no">2740</span><span id="line-2740">    }</span>
-<span class="source-line-no">2741</span><span id="line-2741">  }</span>
-<span class="source-line-no">2742</span><span id="line-2742"></span>
-<span class="source-line-no">2743</span><span id="line-2743">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "DLS_DEAD_LOCAL_STORE",</span>
-<span class="source-line-no">2744</span><span id="line-2744">      justification = "FindBugs seems confused about trxId")</span>
-<span class="source-line-no">2745</span><span id="line-2745">  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,</span>
-<span class="source-line-no">2746</span><span id="line-2746">    Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,</span>
-<span class="source-line-no">2747</span><span id="line-2747">    FlushLifeCycleTracker tracker) throws IOException {</span>
-<span class="source-line-no">2748</span><span id="line-2748">    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {</span>
-<span class="source-line-no">2749</span><span id="line-2749">      // Don't flush when server aborting, it's unsafe</span>
-<span class="source-line-no">2750</span><span id="line-2750">      throw new IOException("Aborting flush because server is aborted...");</span>
-<span class="source-line-no">2751</span><span id="line-2751">    }</span>
-<span class="source-line-no">2752</span><span id="line-2752">    final long startTime = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">2753</span><span id="line-2753">    // If nothing to flush, return, but return with a valid unused sequenceId.</span>
-<span class="source-line-no">2754</span><span id="line-2754">    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a</span>
-<span class="source-line-no">2755</span><span id="line-2755">    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs</span>
-<span class="source-line-no">2756</span><span id="line-2756">    // to no other that it can use to associate with the bulk load. Hence this little dance below</span>
-<span class="source-line-no">2757</span><span id="line-2757">    // to go get one.</span>
-<span class="source-line-no">2758</span><span id="line-2758">    if (this.memStoreSizing.getDataSize() &lt;= 0) {</span>
-<span class="source-line-no">2759</span><span id="line-2759">      // Take an update lock so no edits can come into memory just yet.</span>
-<span class="source-line-no">2760</span><span id="line-2760">      this.updatesLock.writeLock().lock();</span>
-<span class="source-line-no">2761</span><span id="line-2761">      WriteEntry writeEntry = null;</span>
-<span class="source-line-no">2762</span><span id="line-2762">      try {</span>
-<span class="source-line-no">2763</span><span id="line-2763">        if (this.memStoreSizing.getDataSize() &lt;= 0) {</span>
-<span class="source-line-no">2764</span><span id="line-2764">          // Presume that if there are still no edits in the memstore, then there are no edits for</span>
-<span class="source-line-no">2765</span><span id="line-2765">          // this region out in the WAL subsystem so no need to do any trickery clearing out</span>
-<span class="source-line-no">2766</span><span id="line-2766">          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for</span>
-<span class="source-line-no">2767</span><span id="line-2767">          // sure just beyond the last appended region edit and not associated with any edit</span>
-<span class="source-line-no">2768</span><span id="line-2768">          // (useful as marker when bulk loading, etc.).</span>
-<span class="source-line-no">2769</span><span id="line-2769">          if (wal != null) {</span>
-<span class="source-line-no">2770</span><span id="line-2770">            writeEntry = mvcc.begin();</span>
-<span class="source-line-no">2771</span><span id="line-2771">            long flushOpSeqId = writeEntry.getWriteNumber();</span>
-<span class="source-line-no">2772</span><span id="line-2772">            FlushResultImpl flushResult = new FlushResultImpl(</span>
-<span class="source-line-no">2773</span><span id="line-2773">              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId, "Nothing to flush",</span>
-<span class="source-line-no">2774</span><span id="line-2774">              writeCanNotFlushMarkerToWAL(writeEntry, wal, writeFlushWalMarker));</span>
-<span class="source-line-no">2775</span><span id="line-2775">            mvcc.completeAndWait(writeEntry);</span>
-<span class="source-line-no">2776</span><span id="line-2776">            // Set to null so we don't complete it again down in finally block.</span>
-<span class="source-line-no">2777</span><span id="line-2777">            writeEntry = null;</span>
-<span class="source-line-no">2778</span><span id="line-2778">            return new PrepareFlushResult(flushResult, myseqid);</span>
-<span class="source-line-no">2779</span><span id="line-2779">          } else {</span>
-<span class="source-line-no">2780</span><span id="line-2780">            return new PrepareFlushResult(new FlushResultImpl(</span>
-<span class="source-line-no">2781</span><span id="line-2781">              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);</span>
-<span class="source-line-no">2782</span><span id="line-2782">          }</span>
-<span class="source-line-no">2783</span><span id="line-2783">        }</span>
-<span class="source-line-no">2784</span><span id="line-2784">      } finally {</span>
-<span class="source-line-no">2785</span><span id="line-2785">        if (writeEntry != null) {</span>
-<span class="source-line-no">2786</span><span id="line-2786">          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...</span>
-<span class="source-line-no">2787</span><span id="line-2787">          // but complete it anyways so it doesn't block the mvcc queue.</span>
-<span class="source-line-no">2788</span><span id="line-2788">          mvcc.complete(writeEntry);</span>
-<span class="source-line-no">2789</span><span id="line-2789">        }</span>
-<span class="source-line-no">2790</span><span id="line-2790">        this.updatesLock.writeLock().unlock();</span>
-<span class="source-line-no">2791</span><span id="line-2791">      }</span>
-<span class="source-line-no">2792</span><span id="line-2792">    }</span>
-<span class="source-line-no">2793</span><span id="line-2793">    logFatLineOnFlush(storesToFlush, myseqid);</span>
-<span class="source-line-no">2794</span><span id="line-2794">    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have</span>
-<span class="source-line-no">2795</span><span id="line-2795">    // to do this for a moment. It is quick. We also set the memstore size to zero here before we</span>
-<span class="source-line-no">2796</span><span id="line-2796">    // allow updates again so its value will represent the size of the updates received</span>
-<span class="source-line-no">2797</span><span id="line-2797">    // during flush</span>
-<span class="source-line-no">2798</span><span id="line-2798"></span>
-<span class="source-line-no">2799</span><span id="line-2799">    // We have to take an update lock during snapshot, or else a write could end up in both snapshot</span>
-<span class="source-line-no">2800</span><span id="line-2800">    // and memstore (makes it difficult to do atomic rows then)</span>
-<span class="source-line-no">2801</span><span id="line-2801">    status.setStatus("Obtaining lock to block concurrent updates");</span>
-<span class="source-line-no">2802</span><span id="line-2802">    // block waiting for the lock for internal flush</span>
-<span class="source-line-no">2803</span><span id="line-2803">    this.updatesLock.writeLock().lock();</span>
-<span class="source-line-no">2804</span><span id="line-2804">    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());</span>
-<span class="source-line-no">2805</span><span id="line-2805">    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();</span>
-<span class="source-line-no">2806</span><span id="line-2806"></span>
-<span class="source-line-no">2807</span><span id="line-2807">    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();</span>
-<span class="source-line-no">2808</span><span id="line-2808">    for (HStore store : storesToFlush) {</span>
-<span class="source-line-no">2809</span><span id="line-2809">      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),</span>
-<span class="source-line-no">2810</span><span id="line-2810">        store.preFlushSeqIDEstimation());</span>
-<span class="source-line-no">2811</span><span id="line-2811">    }</span>
-<span class="source-line-no">2812</span><span id="line-2812"></span>
-<span class="source-line-no">2813</span><span id="line-2813">    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
-<span class="source-line-no">2814</span><span id="line-2814">    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
-<span class="source-line-no">2815</span><span id="line-2815">    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
-<span class="source-line-no">2816</span><span id="line-2816">    // The sequence id of this flush operation which is used to log FlushMarker and pass to</span>
-<span class="source-line-no">2817</span><span id="line-2817">    // createFlushContext to use as the store file's sequence id. It can be in advance of edits</span>
-<span class="source-line-no">2818</span><span id="line-2818">    // still in the memstore, edits that are in other column families yet to be flushed.</span>
-<span class="source-line-no">2819</span><span id="line-2819">    long flushOpSeqId = HConstants.NO_SEQNUM;</span>
-<span class="source-line-no">2820</span><span id="line-2820">    // The max flushed sequence id after this flush operation completes. All edits in memstore</span>
-<span class="source-line-no">2821</span><span id="line-2821">    // will be in advance of this sequence id.</span>
-<span class="source-line-no">2822</span><span id="line-2822">    long flushedSeqId = HConstants.NO_SEQNUM;</span>
-<span class="source-line-no">2823</span><span id="line-2823">    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();</span>
-<span class="source-line-no">2824</span><span id="line-2824">    try {</span>
-<span class="source-line-no">2825</span><span id="line-2825">      if (wal != null) {</span>
-<span class="source-line-no">2826</span><span id="line-2826">        Long earliestUnflushedSequenceIdForTheRegion =</span>
-<span class="source-line-no">2827</span><span id="line-2827">          wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);</span>
-<span class="source-line-no">2828</span><span id="line-2828">        if (earliestUnflushedSequenceIdForTheRegion == null) {</span>
-<span class="source-line-no">2829</span><span id="line-2829">          // This should never happen. This is how startCacheFlush signals flush cannot proceed.</span>
-<span class="source-line-no">2830</span><span id="line-2830">          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";</span>
-<span class="source-line-no">2831</span><span id="line-2831">          status.setStatus(msg);</span>
-<span class="source-line-no">2832</span><span id="line-2832">          return new PrepareFlushResult(</span>
-<span class="source-line-no">2833</span><span id="line-2833">            new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false), myseqid);</span>
-<span class="source-line-no">2834</span><span id="line-2834">        }</span>
-<span class="source-line-no">2835</span><span id="line-2835">        flushOpSeqId = getNextSequenceId(wal);</span>
-<span class="source-line-no">2836</span><span id="line-2836">        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit</span>
-<span class="source-line-no">2837</span><span id="line-2837">        flushedSeqId = earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM</span>
-<span class="source-line-no">2838</span><span id="line-2838">          ? flushOpSeqId</span>
-<span class="source-line-no">2839</span><span id="line-2839">          : earliestUnflushedSequenceIdForTheRegion.longValue() - 1;</span>
-<span class="source-line-no">2840</span><span id="line-2840">      } else {</span>
-<span class="source-line-no">2841</span><span id="line-2841">        // use the provided sequence Id as WAL is not being used for this flush.</span>
-<span class="source-line-no">2842</span><span id="line-2842">        flushedSeqId = flushOpSeqId = myseqid;</span>
-<span class="source-line-no">2843</span><span id="line-2843">      }</span>
-<span class="source-line-no">2844</span><span id="line-2844"></span>
-<span class="source-line-no">2845</span><span id="line-2845">      for (HStore s : storesToFlush) {</span>
-<span class="source-line-no">2846</span><span id="line-2846">        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),</span>
-<span class="source-line-no">2847</span><span id="line-2847">          s.createFlushContext(flushOpSeqId, tracker));</span>
-<span class="source-line-no">2848</span><span id="line-2848">        // for writing stores to WAL</span>
-<span class="source-line-no">2849</span><span id="line-2849">        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);</span>
-<span class="source-line-no">2850</span><span id="line-2850">      }</span>
-<span class="source-line-no">2851</span><span id="line-2851"></span>
-<span class="source-line-no">2852</span><span id="line-2852">      // write the snapshot start to WAL</span>
-<span class="source-line-no">2853</span><span id="line-2853">      if (wal != null &amp;&amp; !writestate.readOnly) {</span>
-<span class="source-line-no">2854</span><span id="line-2854">        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,</span>
-<span class="source-line-no">2855</span><span id="line-2855">          getRegionInfo(), flushOpSeqId, committedFiles);</span>
-<span class="source-line-no">2856</span><span id="line-2856">        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH</span>
-<span class="source-line-no">2857</span><span id="line-2857">        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,</span>
-<span class="source-line-no">2858</span><span id="line-2858">          mvcc, regionReplicationSink.orElse(null));</span>
-<span class="source-line-no">2859</span><span id="line-2859">      }</span>
-<span class="source-line-no">2860</span><span id="line-2860"></span>
-<span class="source-line-no">2861</span><span id="line-2861">      // Prepare flush (take a snapshot)</span>
-<span class="source-line-no">2862</span><span id="line-2862">      storeFlushCtxs.forEach((name, flush) -&gt; {</span>
-<span class="source-line-no">2863</span><span id="line-2863">        MemStoreSize snapshotSize = flush.prepare();</span>
-<span class="source-line-no">2864</span><span id="line-2864">        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);</span>
-<span class="source-line-no">2865</span><span id="line-2865">        storeFlushableSize.put(name, snapshotSize);</span>
-<span class="source-line-no">2866</span><span id="line-2866">      });</span>
-<span class="source-line-no">2867</span><span id="line-2867">    } catch (IOException ex) {</span>
-<span class="source-line-no">2868</span><span id="line-2868">      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);</span>
-<span class="source-line-no">2869</span><span id="line-2869">      throw ex;</span>
-<span class="source-line-no">2870</span><span id="line-2870">    } finally {</span>
-<span class="source-line-no">2871</span><span id="line-2871">      this.updatesLock.writeLock().unlock();</span>
-<span class="source-line-no">2872</span><span id="line-2872">    }</span>
-<span class="source-line-no">2873</span><span id="line-2873">    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, "</span>
-<span class="source-line-no">2874</span><span id="line-2874">      + "flushsize=" + totalSizeOfFlushableStores;</span>
-<span class="source-line-no">2875</span><span id="line-2875">    status.setStatus(s);</span>
-<span class="source-line-no">2876</span><span id="line-2876">    doSyncOfUnflushedWALChanges(wal, getRegionInfo());</span>
-<span class="source-line-no">2877</span><span id="line-2877">    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,</span>
-<span class="source-line-no">2878</span><span id="line-2878">      flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);</span>
-<span class="source-line-no">2879</span><span id="line-2879">  }</span>
-<span class="source-line-no">2880</span><span id="line-2880"></span>
-<span class="source-line-no">2881</span><span id="line-2881">  /**</span>
-<span class="source-line-no">2882</span><span id="line-2882">   * Utility method broken out of internalPrepareFlushCache so that method is smaller.</span>
-<span class="source-line-no">2883</span><span id="line-2883">   */</span>
-<span class="source-line-no">2884</span><span id="line-2884">  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {</span>
-<span class="source-line-no">2885</span><span id="line-2885">    if (!LOG.isInfoEnabled()) {</span>
-<span class="source-line-no">2886</span><span id="line-2886">      return;</span>
-<span class="source-line-no">2887</span><span id="line-2887">    }</span>
-<span class="source-line-no">2888</span><span id="line-2888">    // Log a fat line detailing what is being flushed.</span>
-<span class="source-line-no">2889</span><span id="line-2889">    StringBuilder perCfExtras = null;</span>
-<span class="source-line-no">2890</span><span id="line-2890">    if (!isAllFamilies(storesToFlush)) {</span>
-<span class="source-line-no">2891</span><span id="line-2891">      perCfExtras = new StringBuilder();</span>
-<span class="source-line-no">2892</span><span id="line-2892">      for (HStore store : storesToFlush) {</span>
-<span class="source-line-no">2893</span><span id="line-2893">        MemStoreSize mss = store.getFlushableSize();</span>
-<span class="source-line-no">2894</span><span id="line-2894">        perCfExtras.append("; ").append(store.getColumnFamilyName());</span>
-<span class="source-line-no">2895</span><span id="line-2895">        perCfExtras.append("={dataSize=").append(StringUtils.byteDesc(mss.getDataSize()));</span>
-<span class="source-line-no">2896</span><span id="line-2896">        perCfExtras.append(", heapSize=").append(StringUtils.byteDesc(mss.getHeapSize()));</span>
-<span class="source-line-no">2897</span><span id="line-2897">        perCfExtras.append(", offHeapSize=").append(StringUtils.byteDesc(mss.getOffHeapSize()));</span>
-<span class="source-line-no">2898</span><span id="line-2898">        perCfExtras.append("}");</span>
-<span class="source-line-no">2899</span><span id="line-2899">      }</span>
-<span class="source-line-no">2900</span><span id="line-2900">    }</span>
-<span class="source-line-no">2901</span><span id="line-2901">    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();</span>
-<span class="source-line-no">2902</span><span id="line-2902">    LOG.info("Flushing " + this.getRegionInfo().getEncodedName() + " " + storesToFlush.size() + "/"</span>
-<span class="source-line-no">2903</span><span id="line-2903">      + stores.size() + " column families," + " dataSize=" + StringUtils.byteDesc(mss.getDataSize())</span>
-<span class="source-line-no">2904</span><span id="line-2904">      + " heapSize=" + StringUtils.byteDesc(mss.getHeapSize())</span>
-<span class="source-line-no">2905</span><span id="line-2905">      + ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0) ? perCfExtras.toString() : "")</span>
-<span class="source-line-no">2906</span><span id="line-2906">      + ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));</span>
-<span class="source-line-no">2907</span><span id="line-2907">  }</span>
-<span class="source-line-no">2908</span><span id="line-2908"></span>
-<span class="source-line-no">2909</span><span id="line-2909">  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,</span>
-<span class="source-line-no">2910</span><span id="line-2910">    final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {</span>
-<span class="source-line-no">2911</span><span id="line-2911">    if (wal == null) return;</span>
-<span class="source-line-no">2912</span><span id="line-2912">    try {</span>
-<span class="source-line-no">2913</span><span id="line-2913">      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,</span>
-<span class="source-line-no">2914</span><span id="line-2914">        getRegionInfo(), flushOpSeqId, committedFiles);</span>
-<span class="source-line-no">2915</span><span id="line-2915">      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false, mvcc,</span>
-<span class="source-line-no">2916</span><span id="line-2916">        null);</span>
-<span class="source-line-no">2917</span><span id="line-2917">    } catch (Throwable t) {</span>
-<span class="source-line-no">2918</span><span id="line-2918">      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL: {} in "</span>
-<span class="source-line-no">2919</span><span id="line-2919">        + " region {}", StringUtils.stringifyException(t), this);</span>
-<span class="source-line-no">2920</span><span id="line-2920">      // ignore this since we will be aborting the RS with DSE.</span>
-<span class="source-line-no">2921</span><span id="line-2921">    }</span>
-<span class="source-line-no">2922</span><span id="line-2922">    // we have called wal.startCacheFlush(), now we have to abort it</span>
-<span class="source-line-no">2923</span><span id="line-2923">    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());</span>
-<span class="source-line-no">2924</span><span id="line-2924">  }</span>
-<span class="source-line-no">2925</span><span id="line-2925"></span>
-<span class="source-line-no">2926</span><span id="line-2926">  /**</span>
-<span class="source-line-no">2927</span><span id="line-2927">   * Sync unflushed WAL changes. See HBASE-8208 for details</span>
-<span class="source-line-no">2928</span><span id="line-2928">   */</span>
-<span class="source-line-no">2929</span><span id="line-2929">  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)</span>
-<span class="source-line-no">2930</span><span id="line-2930">    throws IOException {</span>
-<span class="source-line-no">2931</span><span id="line-2931">    if (wal == null) {</span>
-<span class="source-line-no">2932</span><span id="line-2932">      return;</span>
-<span class="source-line-no">2933</span><span id="line-2933">    }</span>
-<span class="source-line-no">2934</span><span id="line-2934">    try {</span>
-<span class="source-line-no">2935</span><span id="line-2935">      wal.sync(); // ensure that flush marker is sync'ed</span>
-<span class="source-line-no">2936</span><span id="line-2936">    } catch (IOException ioe) {</span>
-<span class="source-line-no">2937</span><span id="line-2937">      wal.abortCacheFlush(hri.getEncodedNameAsBytes());</span>
-<span class="source-line-no">2938</span><span id="line-2938">      throw ioe;</span>
-<span class="source-line-no">2939</span><span id="line-2939">    }</span>
-<span class="source-line-no">2940</span><span id="line-2940">  }</span>
-<span class="source-line-no">2941</span><span id="line-2941"></span>
-<span class="source-line-no">2942</span><span id="line-2942">  /** Returns True if passed Set is all families in the region. */</span>
-<span class="source-line-no">2943</span><span id="line-2943">  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {</span>
-<span class="source-line-no">2944</span><span id="line-2944">    return families == null || this.stores.size() == families.size();</span>
-<span class="source-line-no">2945</span><span id="line-2945">  }</span>
-<span class="source-line-no">2946</span><span id="line-2946"></span>
-<span class="source-line-no">2947</span><span id="line-2947">  /**</span>
-<span class="source-line-no">2948</span><span id="line-2948">   * This method is only used when we flush but the memstore is empty,if writeFlushWalMarker is</span>
-<span class="source-line-no">2949</span><span id="line-2949">   * true,we write the {@link FlushAction#CANNOT_FLUSH} flush marker to WAL when the memstore is</span>
-<span class="source-line-no">2950</span><span id="line-2950">   * empty. Ignores exceptions from WAL. Returns whether the write succeeded.</span>
-<span class="source-line-no">2951</span><span id="line-2951">   * @return whether WAL write was successful</span>
-<span class="source-line-no">2952</span><span id="line-2952">   */</span>
-<span class="source-line-no">2953</span><span id="line-2953">  private boolean writeCanNotFlushMarkerToWAL(WriteEntry flushOpSeqIdMVCCEntry, WAL wal,</span>
-<span class="source-line-no">2954</span><span id="line-2954">    boolean writeFlushWalMarker) {</span>
-<span class="source-line-no">2955</span><span id="line-2955">    FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH, getRegionInfo(),</span>
-<span class="source-line-no">2956</span><span id="line-2956">      -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));</span>
-<span class="source-line-no">2957</span><span id="line-2957">    RegionReplicationSink sink = regionReplicationSink.orElse(null);</span>
-<span class="source-line-no">2958</span><span id="line-2958"></span>
-<span class="source-line-no">2959</span><span id="line-2959">    if (sink != null &amp;&amp; !writeFlushWalMarker) {</span>
-<span class="source-line-no">2960</span><span id="line-2960">      /**</span>
-<span class="source-line-no">2961</span><span id="line-2961">       * Here for replication to secondary region replica could use {@link FlushAction#CANNOT_FLUSH}</span>
-<span class="source-line-no">2962</span><span id="line-2962">       * to recover when writeFlushWalMarker is false, we create {@link WALEdit} for</span>
-<span class="source-line-no">2963</span><span id="line-2963">       * {@link FlushDescriptor} and attach the {@link RegionReplicationSink#add} to the</span>
-<span class="source-line-no">2964</span><span id="line-2964">       * flushOpSeqIdMVCCEntry,see HBASE-26960 for more details.</span>
-<span class="source-line-no">2965</span><span id="line-2965">       */</span>
-<span class="source-line-no">2966</span><span id="line-2966">      this.attachRegionReplicationToFlushOpSeqIdMVCCEntry(flushOpSeqIdMVCCEntry, desc, sink);</span>
-<span class="source-line-no">2967</span><span id="line-2967">      return false;</span>
-<span class="source-line-no">2968</span><span id="line-2968">    }</span>
-<span class="source-line-no">2969</span><span id="line-2969"></span>
-<span class="source-line-no">2970</span><span id="line-2970">    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {</span>
-<span class="source-line-no">2971</span><span id="line-2971">      try {</span>
-<span class="source-line-no">2972</span><span id="line-2972">        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true, mvcc,</span>
-<span class="source-line-no">2973</span><span id="line-2973">          sink);</span>
-<span class="source-line-no">2974</span><span id="line-2974">        return true;</span>
-<span class="source-line-no">2975</span><span id="line-2975">      } catch (IOException e) {</span>
-<span class="source-line-no">2976</span><span id="line-2976">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">2977</span><span id="line-2977">          + "Received exception while trying to write the flush request to wal", e);</span>
-<span class="source-line-no">2978</span><span id="line-2978">      }</span>
-<span class="source-line-no">2979</span><span id="line-2979">    }</span>
-<span class="source-line-no">2980</span><span id="line-2980">    return false;</span>
-<span class="source-line-no">2981</span><span id="line-2981">  }</span>
-<span class="source-line-no">2982</span><span id="line-2982"></span>
-<span class="source-line-no">2983</span><span id="line-2983">  /**</span>
-<span class="source-line-no">2984</span><span id="line-2984">   * Create {@link WALEdit} for {@link FlushDescriptor} and attach {@link RegionReplicationSink#add}</span>
-<span class="source-line-no">2985</span><span id="line-2985">   * to the flushOpSeqIdMVCCEntry.</span>
-<span class="source-line-no">2986</span><span id="line-2986">   */</span>
-<span class="source-line-no">2987</span><span id="line-2987">  private void attachRegionReplicationToFlushOpSeqIdMVCCEntry(WriteEntry flushOpSeqIdMVCCEntry,</span>
-<span class="source-line-no">2988</span><span id="line-2988">    FlushDescriptor desc, RegionReplicationSink sink) {</span>
-<span class="source-line-no">2989</span><span id="line-2989">    assert !flushOpSeqIdMVCCEntry.getCompletionAction().isPresent();</span>
-<span class="source-line-no">2990</span><span id="line-2990">    WALEdit flushMarkerWALEdit = WALEdit.createFlushWALEdit(getRegionInfo(), desc);</span>
-<span class="source-line-no">2991</span><span id="line-2991">    WALKeyImpl walKey =</span>
-<span class="source-line-no">2992</span><span id="line-2992">      WALUtil.createWALKey(getRegionInfo(), mvcc, this.getReplicationScope(), null);</span>
-<span class="source-line-no">2993</span><span id="line-2993">    walKey.setWriteEntry(flushOpSeqIdMVCCEntry);</span>
-<span class="source-line-no">2994</span><span id="line-2994">    /**</span>
-<span class="source-line-no">2995</span><span id="line-2995">     * Here the {@link ServerCall} is null for {@link RegionReplicationSink#add} because the</span>
-<span class="source-line-no">2996</span><span id="line-2996">     * flushMarkerWALEdit is created by ourselves, not from rpc.</span>
-<span class="source-line-no">2997</span><span id="line-2997">     */</span>
-<span class="source-line-no">2998</span><span id="line-2998">    flushOpSeqIdMVCCEntry.attachCompletionAction(() -&gt; sink.add(walKey, flushMarkerWALEdit, null));</span>
-<span class="source-line-no">2999</span><span id="line-2999">  }</span>
-<span class="source-line-no">3000</span><span id="line-3000"></span>
-<span class="source-line-no">3001</span><span id="line-3001">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",</span>
-<span class="source-line-no">3002</span><span id="line-3002">      justification = "Intentional; notify is about completed flush")</span>
-<span class="source-line-no">3003</span><span id="line-3003">  FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,</span>
-<span class="source-line-no">3004</span><span id="line-3004">    PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {</span>
-<span class="source-line-no">3005</span><span id="line-3005">    // prepare flush context is carried via PrepareFlushResult</span>
-<span class="source-line-no">3006</span><span id="line-3006">    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;</span>
-<span class="source-line-no">3007</span><span id="line-3007">    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;</span>
-<span class="source-line-no">3008</span><span id="line-3008">    long startTime = prepareResult.startTime;</span>
-<span class="source-line-no">3009</span><span id="line-3009">    long flushOpSeqId = prepareResult.flushOpSeqId;</span>
-<span class="source-line-no">3010</span><span id="line-3010">    long flushedSeqId = prepareResult.flushedSeqId;</span>
-<span class="source-line-no">3011</span><span id="line-3011"></span>
-<span class="source-line-no">3012</span><span id="line-3012">    String s = "Flushing stores of " + this;</span>
-<span class="source-line-no">3013</span><span id="line-3013">    status.setStatus(s);</span>
-<span class="source-line-no">3014</span><span id="line-3014">    if (LOG.isTraceEnabled()) LOG.trace(s);</span>
-<span class="source-line-no">3015</span><span id="line-3015"></span>
-<span class="source-line-no">3016</span><span id="line-3016">    // Any failure from here on out will be catastrophic requiring server</span>
-<span class="source-line-no">3017</span><span id="line-3017">    // restart so wal content can be replayed and put back into the memstore.</span>
-<span class="source-line-no">3018</span><span id="line-3018">    // Otherwise, the snapshot content while backed up in the wal, it will not</span>
-<span class="source-line-no">3019</span><span id="line-3019">    // be part of the current running servers state.</span>
-<span class="source-line-no">3020</span><span id="line-3020">    boolean compactionRequested = false;</span>
-<span class="source-line-no">3021</span><span id="line-3021">    long flushedOutputFileSize = 0;</span>
-<span class="source-line-no">3022</span><span id="line-3022">    try {</span>
-<span class="source-line-no">3023</span><span id="line-3023">      // A. Flush memstore to all the HStores.</span>
-<span class="source-line-no">3024</span><span id="line-3024">      // Keep running vector of all store files that includes both old and the</span>
-<span class="source-line-no">3025</span><span id="line-3025">      // just-made new flush store file. The new flushed file is still in the</span>
-<span class="source-line-no">3026</span><span id="line-3026">      // tmp directory.</span>
-<span class="source-line-no">3027</span><span id="line-3027"></span>
-<span class="source-line-no">3028</span><span id="line-3028">      for (StoreFlushContext flush : storeFlushCtxs.values()) {</span>
-<span class="source-line-no">3029</span><span id="line-3029">        flush.flushCache(status);</span>
-<span class="source-line-no">3030</span><span id="line-3030">      }</span>
-<span class="source-line-no">3031</span><span id="line-3031"></span>
-<span class="source-line-no">3032</span><span id="line-3032">      // Switch snapshot (in memstore) -&gt; new hfile (thus causing</span>
-<span class="source-line-no">3033</span><span id="line-3033">      // all the store scanners to reset/reseek).</span>
-<span class="source-line-no">3034</span><span id="line-3034">      for (Map.Entry&lt;byte[], StoreFlushContext&gt; flushEntry : storeFlushCtxs.entrySet()) {</span>
-<span class="source-line-no">3035</span><span id="line-3035">        StoreFlushContext sfc = flushEntry.getValue();</span>
-<span class="source-line-no">3036</span><span id="line-3036">        boolean needsCompaction = sfc.commit(status);</span>
-<span class="source-line-no">3037</span><span id="line-3037">        if (needsCompaction) {</span>
-<span class="source-line-no">3038</span><span id="line-3038">          compactionRequested = true;</span>
-<span class="source-line-no">3039</span><span id="line-3039">        }</span>
-<span class="source-line-no">3040</span><span id="line-3040">        byte[] storeName = flushEntry.getKey();</span>
-<span class="source-line-no">3041</span><span id="line-3041">        List&lt;Path&gt; storeCommittedFiles = sfc.getCommittedFiles();</span>
-<span class="source-line-no">3042</span><span id="line-3042">        committedFiles.put(storeName, storeCommittedFiles);</span>
-<span class="source-line-no">3043</span><span id="line-3043">        // Flush committed no files, indicating flush is empty or flush was canceled</span>
-<span class="source-line-no">3044</span><span id="line-3044">        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {</span>
-<span class="source-line-no">3045</span><span id="line-3045">          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);</span>
-<span class="source-line-no">3046</span><span id="line-3046">          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);</span>
-<span class="source-line-no">3047</span><span id="line-3047">        }</span>
-<span class="source-line-no">3048</span><span id="line-3048">        flushedOutputFileSize += sfc.getOutputFileSize();</span>
-<span class="source-line-no">3049</span><span id="line-3049">      }</span>
-<span class="source-line-no">3050</span><span id="line-3050">      storeFlushCtxs.clear();</span>
-<span class="source-line-no">3051</span><span id="line-3051"></span>
-<span class="source-line-no">3052</span><span id="line-3052">      // Set down the memstore size by amount of flush.</span>
-<span class="source-line-no">3053</span><span id="line-3053">      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();</span>
-<span class="source-line-no">3054</span><span id="line-3054">      this.decrMemStoreSize(mss);</span>
-<span class="source-line-no">3055</span><span id="line-3055"></span>
-<span class="source-line-no">3056</span><span id="line-3056">      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.</span>
-<span class="source-line-no">3057</span><span id="line-3057">      // During startup, quota manager may not be initialized yet.</span>
-<span class="source-line-no">3058</span><span id="line-3058">      if (rsServices != null) {</span>
-<span class="source-line-no">3059</span><span id="line-3059">        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();</span>
-<span class="source-line-no">3060</span><span id="line-3060">        if (quotaManager != null) {</span>
-<span class="source-line-no">3061</span><span id="line-3061">          quotaManager.getRegionSizeStore().incrementRegionSize(this.getRegionInfo(),</span>
-<span class="source-line-no">3062</span><span id="line-3062">            flushedOutputFileSize);</span>
-<span class="source-line-no">3063</span><span id="line-3063">        }</span>
-<span class="source-line-no">3064</span><span id="line-3064">      }</span>
-<span class="source-line-no">3065</span><span id="line-3065"></span>
-<span class="source-line-no">3066</span><span id="line-3066">      if (wal != null) {</span>
-<span class="source-line-no">3067</span><span id="line-3067">        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException</span>
-<span class="source-line-no">3068</span><span id="line-3068">        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,</span>
-<span class="source-line-no">3069</span><span id="line-3069">          getRegionInfo(), flushOpSeqId, committedFiles);</span>
-<span class="source-line-no">3070</span><span id="line-3070">        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true, mvcc,</span>
-<span class="source-line-no">3071</span><span id="line-3071">          regionReplicationSink.orElse(null));</span>
-<span class="source-line-no">3072</span><span id="line-3072">      }</span>
-<span class="source-line-no">3073</span><span id="line-3073">    } catch (Throwable t) {</span>
-<span class="source-line-no">3074</span><span id="line-3074">      // An exception here means that the snapshot was not persisted.</span>
-<span class="source-line-no">3075</span><span id="line-3075">      // The wal needs to be replayed so its content is restored to memstore.</span>
-<span class="source-line-no">3076</span><span id="line-3076">      // Currently, only a server restart will do this.</span>
-<span class="source-line-no">3077</span><span id="line-3077">      // We used to only catch IOEs but its possible that we'd get other</span>
-<span class="source-line-no">3078</span><span id="line-3078">      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch</span>
-<span class="source-line-no">3079</span><span id="line-3079">      // all and sundry.</span>
-<span class="source-line-no">3080</span><span id="line-3080">      if (wal != null) {</span>
-<span class="source-line-no">3081</span><span id="line-3081">        try {</span>
-<span class="source-line-no">3082</span><span id="line-3082">          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,</span>
-<span class="source-line-no">3083</span><span id="line-3083">            getRegionInfo(), flushOpSeqId, committedFiles);</span>
-<span class="source-line-no">3084</span><span id="line-3084">          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc,</span>
-<span class="source-line-no">3085</span><span id="line-3085">            null);</span>
-<span class="source-line-no">3086</span><span id="line-3086">        } catch (Throwable ex) {</span>
-<span class="source-line-no">3087</span><span id="line-3087">          LOG.warn(</span>
-<span class="source-line-no">3088</span><span id="line-3088">            getRegionInfo().getEncodedName() + " : " + "failed writing ABORT_FLUSH marker to WAL",</span>
-<span class="source-line-no">3089</span><span id="line-3089">            ex);</span>
-<span class="source-line-no">3090</span><span id="line-3090">          // ignore this since we will be aborting the RS with DSE.</span>
-<span class="source-line-no">3091</span><span id="line-3091">        }</span>
-<span class="source-line-no">3092</span><span id="line-3092">        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());</span>
+<span class="source-line-no">2741</span><span id="line-2741">    long now = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">2742</span><span id="line-2742">    // if we flushed in the recent past, we don't need to do again now</span>
+<span class="source-line-no">2743</span><span id="line-2743">    if ((now - getEarliestFlushTimeForAllStores() &lt; modifiedFlushCheckInterval)) {</span>
+<span class="source-line-no">2744</span><span id="line-2744">      return false;</span>
+<span class="source-line-no">2745</span><span id="line-2745">    }</span>
+<span class="source-line-no">2746</span><span id="line-2746">    // since we didn't flush in the recent past, flush now if certain conditions</span>
+<span class="source-line-no">2747</span><span id="line-2747">    // are met. Return true on first such memstore hit.</span>
+<span class="source-line-no">2748</span><span id="line-2748">    for (HStore s : stores.values()) {</span>
+<span class="source-line-no">2749</span><span id="line-2749">      if (s.timeOfOldestEdit() &lt; now - modifiedFlushCheckInterval) {</span>
+<span class="source-line-no">2750</span><span id="line-2750">        // we have an old enough edit in the memstore, flush</span>
+<span class="source-line-no">2751</span><span id="line-2751">        whyFlush.append(s.toString() + " has an old edit so flush to free WALs");</span>
+<span class="source-line-no">2752</span><span id="line-2752">        return true;</span>
+<span class="source-line-no">2753</span><span id="line-2753">      }</span>
+<span class="source-line-no">2754</span><span id="line-2754">    }</span>
+<span class="source-line-no">2755</span><span id="line-2755">    return false;</span>
+<span class="source-line-no">2756</span><span id="line-2756">  }</span>
+<span class="source-line-no">2757</span><span id="line-2757"></span>
+<span class="source-line-no">2758</span><span id="line-2758">  /**</span>
+<span class="source-line-no">2759</span><span id="line-2759">   * Flushing all stores.</span>
+<span class="source-line-no">2760</span><span id="line-2760">   * @see #internalFlushcache(Collection, MonitoredTask, boolean, FlushLifeCycleTracker)</span>
+<span class="source-line-no">2761</span><span id="line-2761">   */</span>
+<span class="source-line-no">2762</span><span id="line-2762">  private FlushResult internalFlushcache(MonitoredTask status) throws IOException {</span>
+<span class="source-line-no">2763</span><span id="line-2763">    return internalFlushcache(stores.values(), status, false, FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">2764</span><span id="line-2764">  }</span>
+<span class="source-line-no">2765</span><span id="line-2765"></span>
+<span class="source-line-no">2766</span><span id="line-2766">  /**</span>
+<span class="source-line-no">2767</span><span id="line-2767">   * Flushing given stores.</span>
+<span class="source-line-no">2768</span><span id="line-2768">   * @see #internalFlushcache(WAL, long, Collection, MonitoredTask, boolean, FlushLifeCycleTracker)</span>
+<span class="source-line-no">2769</span><span id="line-2769">   */</span>
+<span class="source-line-no">2770</span><span id="line-2770">  private FlushResultImpl internalFlushcache(Collection&lt;HStore&gt; storesToFlush, MonitoredTask status,</span>
+<span class="source-line-no">2771</span><span id="line-2771">    boolean writeFlushWalMarker, FlushLifeCycleTracker tracker) throws IOException {</span>
+<span class="source-line-no">2772</span><span id="line-2772">    return internalFlushcache(this.wal, HConstants.NO_SEQNUM, storesToFlush, status,</span>
+<span class="source-line-no">2773</span><span id="line-2773">      writeFlushWalMarker, tracker);</span>
+<span class="source-line-no">2774</span><span id="line-2774">  }</span>
+<span class="source-line-no">2775</span><span id="line-2775"></span>
+<span class="source-line-no">2776</span><span id="line-2776">  /**</span>
+<span class="source-line-no">2777</span><span id="line-2777">   * Flush the memstore. Flushing the memstore is a little tricky. We have a lot of updates in the</span>
+<span class="source-line-no">2778</span><span id="line-2778">   * memstore, all of which have also been written to the wal. We need to write those updates in the</span>
+<span class="source-line-no">2779</span><span id="line-2779">   * memstore out to disk, while being able to process reads/writes as much as possible during the</span>
+<span class="source-line-no">2780</span><span id="line-2780">   * flush operation.</span>
+<span class="source-line-no">2781</span><span id="line-2781">   * &lt;p&gt;</span>
+<span class="source-line-no">2782</span><span id="line-2782">   * This method may block for some time. Every time you call it, we up the regions sequence id even</span>
+<span class="source-line-no">2783</span><span id="line-2783">   * if we don't flush; i.e. the returned region id will be at least one larger than the last edit</span>
+<span class="source-line-no">2784</span><span id="line-2784">   * applied to this region. The returned id does not refer to an actual edit. The returned id can</span>
+<span class="source-line-no">2785</span><span id="line-2785">   * be used for say installing a bulk loaded file just ahead of the last hfile that was the result</span>
+<span class="source-line-no">2786</span><span id="line-2786">   * of this flush, etc.</span>
+<span class="source-line-no">2787</span><span id="line-2787">   * @param wal           Null if we're NOT to go via wal.</span>
+<span class="source-line-no">2788</span><span id="line-2788">   * @param myseqid       The seqid to use if &lt;code&gt;wal&lt;/code&gt; is null writing out flush file.</span>
+<span class="source-line-no">2789</span><span id="line-2789">   * @param storesToFlush The list of stores to flush.</span>
+<span class="source-line-no">2790</span><span id="line-2790">   * @return object describing the flush's state</span>
+<span class="source-line-no">2791</span><span id="line-2791">   * @throws IOException              general io exceptions</span>
+<span class="source-line-no">2792</span><span id="line-2792">   * @throws DroppedSnapshotException Thrown when replay of WAL is required.</span>
+<span class="source-line-no">2793</span><span id="line-2793">   */</span>
+<span class="source-line-no">2794</span><span id="line-2794">  protected FlushResultImpl internalFlushcache(WAL wal, long myseqid,</span>
+<span class="source-line-no">2795</span><span id="line-2795">    Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,</span>
+<span class="source-line-no">2796</span><span id="line-2796">    FlushLifeCycleTracker tracker) throws IOException {</span>
+<span class="source-line-no">2797</span><span id="line-2797">    PrepareFlushResult result =</span>
+<span class="source-line-no">2798</span><span id="line-2798">      internalPrepareFlushCache(wal, myseqid, storesToFlush, status, writeFlushWalMarker, tracker);</span>
+<span class="source-line-no">2799</span><span id="line-2799">    if (result.result == null) {</span>
+<span class="source-line-no">2800</span><span id="line-2800">      return internalFlushCacheAndCommit(wal, status, result, storesToFlush);</span>
+<span class="source-line-no">2801</span><span id="line-2801">    } else {</span>
+<span class="source-line-no">2802</span><span id="line-2802">      return result.result; // early exit due to failure from prepare stage</span>
+<span class="source-line-no">2803</span><span id="line-2803">    }</span>
+<span class="source-line-no">2804</span><span id="line-2804">  }</span>
+<span class="source-line-no">2805</span><span id="line-2805"></span>
+<span class="source-line-no">2806</span><span id="line-2806">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "DLS_DEAD_LOCAL_STORE",</span>
+<span class="source-line-no">2807</span><span id="line-2807">      justification = "FindBugs seems confused about trxId")</span>
+<span class="source-line-no">2808</span><span id="line-2808">  protected PrepareFlushResult internalPrepareFlushCache(WAL wal, long myseqid,</span>
+<span class="source-line-no">2809</span><span id="line-2809">    Collection&lt;HStore&gt; storesToFlush, MonitoredTask status, boolean writeFlushWalMarker,</span>
+<span class="source-line-no">2810</span><span id="line-2810">    FlushLifeCycleTracker tracker) throws IOException {</span>
+<span class="source-line-no">2811</span><span id="line-2811">    if (this.rsServices != null &amp;&amp; this.rsServices.isAborted()) {</span>
+<span class="source-line-no">2812</span><span id="line-2812">      // Don't flush when server aborting, it's unsafe</span>
+<span class="source-line-no">2813</span><span id="line-2813">      throw new IOException("Aborting flush because server is aborted...");</span>
+<span class="source-line-no">2814</span><span id="line-2814">    }</span>
+<span class="source-line-no">2815</span><span id="line-2815">    final long startTime = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">2816</span><span id="line-2816">    // If nothing to flush, return, but return with a valid unused sequenceId.</span>
+<span class="source-line-no">2817</span><span id="line-2817">    // Its needed by bulk upload IIRC. It flushes until no edits in memory so it can insert a</span>
+<span class="source-line-no">2818</span><span id="line-2818">    // bulk loaded file between memory and existing hfiles. It wants a good seqeunceId that belongs</span>
+<span class="source-line-no">2819</span><span id="line-2819">    // to no other that it can use to associate with the bulk load. Hence this little dance below</span>
+<span class="source-line-no">2820</span><span id="line-2820">    // to go get one.</span>
+<span class="source-line-no">2821</span><span id="line-2821">    if (this.memStoreSizing.getDataSize() &lt;= 0) {</span>
+<span class="source-line-no">2822</span><span id="line-2822">      // Take an update lock so no edits can come into memory just yet.</span>
+<span class="source-line-no">2823</span><span id="line-2823">      this.updatesLock.writeLock().lock();</span>
+<span class="source-line-no">2824</span><span id="line-2824">      WriteEntry writeEntry = null;</span>
+<span class="source-line-no">2825</span><span id="line-2825">      try {</span>
+<span class="source-line-no">2826</span><span id="line-2826">        if (this.memStoreSizing.getDataSize() &lt;= 0) {</span>
+<span class="source-line-no">2827</span><span id="line-2827">          // Presume that if there are still no edits in the memstore, then there are no edits for</span>
+<span class="source-line-no">2828</span><span id="line-2828">          // this region out in the WAL subsystem so no need to do any trickery clearing out</span>
+<span class="source-line-no">2829</span><span id="line-2829">          // edits in the WAL sub-system. Up the sequence number so the resulting flush id is for</span>
+<span class="source-line-no">2830</span><span id="line-2830">          // sure just beyond the last appended region edit and not associated with any edit</span>
+<span class="source-line-no">2831</span><span id="line-2831">          // (useful as marker when bulk loading, etc.).</span>
+<span class="source-line-no">2832</span><span id="line-2832">          if (wal != null) {</span>
+<span class="source-line-no">2833</span><span id="line-2833">            writeEntry = mvcc.begin();</span>
+<span class="source-line-no">2834</span><span id="line-2834">            long flushOpSeqId = writeEntry.getWriteNumber();</span>
+<span class="source-line-no">2835</span><span id="line-2835">            FlushResultImpl flushResult = new FlushResultImpl(</span>
+<span class="source-line-no">2836</span><span id="line-2836">              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId, "Nothing to flush",</span>
+<span class="source-line-no">2837</span><span id="line-2837">              writeCanNotFlushMarkerToWAL(writeEntry, wal, writeFlushWalMarker));</span>
+<span class="source-line-no">2838</span><span id="line-2838">            mvcc.completeAndWait(writeEntry);</span>
+<span class="source-line-no">2839</span><span id="line-2839">            // Set to null so we don't complete it again down in finally block.</span>
+<span class="source-line-no">2840</span><span id="line-2840">            writeEntry = null;</span>
+<span class="source-line-no">2841</span><span id="line-2841">            return new PrepareFlushResult(flushResult, myseqid);</span>
+<span class="source-line-no">2842</span><span id="line-2842">          } else {</span>
+<span class="source-line-no">2843</span><span id="line-2843">            return new PrepareFlushResult(new FlushResultImpl(</span>
+<span class="source-line-no">2844</span><span id="line-2844">              FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, "Nothing to flush", false), myseqid);</span>
+<span class="source-line-no">2845</span><span id="line-2845">          }</span>
+<span class="source-line-no">2846</span><span id="line-2846">        }</span>
+<span class="source-line-no">2847</span><span id="line-2847">      } finally {</span>
+<span class="source-line-no">2848</span><span id="line-2848">        if (writeEntry != null) {</span>
+<span class="source-line-no">2849</span><span id="line-2849">          // If writeEntry is non-null, this operation failed; the mvcc transaction failed...</span>
+<span class="source-line-no">2850</span><span id="line-2850">          // but complete it anyways so it doesn't block the mvcc queue.</span>
+<span class="source-line-no">2851</span><span id="line-2851">          mvcc.complete(writeEntry);</span>
+<span class="source-line-no">2852</span><span id="line-2852">        }</span>
+<span class="source-line-no">2853</span><span id="line-2853">        this.updatesLock.writeLock().unlock();</span>
+<span class="source-line-no">2854</span><span id="line-2854">      }</span>
+<span class="source-line-no">2855</span><span id="line-2855">    }</span>
+<span class="source-line-no">2856</span><span id="line-2856">    logFatLineOnFlush(storesToFlush, myseqid);</span>
+<span class="source-line-no">2857</span><span id="line-2857">    // Stop updates while we snapshot the memstore of all of these regions' stores. We only have</span>
+<span class="source-line-no">2858</span><span id="line-2858">    // to do this for a moment. It is quick. We also set the memstore size to zero here before we</span>
+<span class="source-line-no">2859</span><span id="line-2859">    // allow updates again so its value will represent the size of the updates received</span>
+<span class="source-line-no">2860</span><span id="line-2860">    // during flush</span>
+<span class="source-line-no">2861</span><span id="line-2861"></span>
+<span class="source-line-no">2862</span><span id="line-2862">    // We have to take an update lock during snapshot, or else a write could end up in both snapshot</span>
+<span class="source-line-no">2863</span><span id="line-2863">    // and memstore (makes it difficult to do atomic rows then)</span>
+<span class="source-line-no">2864</span><span id="line-2864">    status.setStatus("Obtaining lock to block concurrent updates");</span>
+<span class="source-line-no">2865</span><span id="line-2865">    // block waiting for the lock for internal flush</span>
+<span class="source-line-no">2866</span><span id="line-2866">    this.updatesLock.writeLock().lock();</span>
+<span class="source-line-no">2867</span><span id="line-2867">    status.setStatus("Preparing flush snapshotting stores in " + getRegionInfo().getEncodedName());</span>
+<span class="source-line-no">2868</span><span id="line-2868">    MemStoreSizing totalSizeOfFlushableStores = new NonThreadSafeMemStoreSizing();</span>
+<span class="source-line-no">2869</span><span id="line-2869"></span>
+<span class="source-line-no">2870</span><span id="line-2870">    Map&lt;byte[], Long&gt; flushedFamilyNamesToSeq = new HashMap&lt;&gt;();</span>
+<span class="source-line-no">2871</span><span id="line-2871">    for (HStore store : storesToFlush) {</span>
+<span class="source-line-no">2872</span><span id="line-2872">      flushedFamilyNamesToSeq.put(store.getColumnFamilyDescriptor().getName(),</span>
+<span class="source-line-no">2873</span><span id="line-2873">        store.preFlushSeqIDEstimation());</span>
+<span class="source-line-no">2874</span><span id="line-2874">    }</span>
+<span class="source-line-no">2875</span><span id="line-2875"></span>
+<span class="source-line-no">2876</span><span id="line-2876">    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
+<span class="source-line-no">2877</span><span id="line-2877">    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
+<span class="source-line-no">2878</span><span id="line-2878">    TreeMap&lt;byte[], MemStoreSize&gt; storeFlushableSize = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
+<span class="source-line-no">2879</span><span id="line-2879">    // The sequence id of this flush operation which is used to log FlushMarker and pass to</span>
+<span class="source-line-no">2880</span><span id="line-2880">    // createFlushContext to use as the store file's sequence id. It can be in advance of edits</span>
+<span class="source-line-no">2881</span><span id="line-2881">    // still in the memstore, edits that are in other column families yet to be flushed.</span>
+<span class="source-line-no">2882</span><span id="line-2882">    long flushOpSeqId = HConstants.NO_SEQNUM;</span>
+<span class="source-line-no">2883</span><span id="line-2883">    // The max flushed sequence id after this flush operation completes. All edits in memstore</span>
+<span class="source-line-no">2884</span><span id="line-2884">    // will be in advance of this sequence id.</span>
+<span class="source-line-no">2885</span><span id="line-2885">    long flushedSeqId = HConstants.NO_SEQNUM;</span>
+<span class="source-line-no">2886</span><span id="line-2886">    byte[] encodedRegionName = getRegionInfo().getEncodedNameAsBytes();</span>
+<span class="source-line-no">2887</span><span id="line-2887">    try {</span>
+<span class="source-line-no">2888</span><span id="line-2888">      if (wal != null) {</span>
+<span class="source-line-no">2889</span><span id="line-2889">        Long earliestUnflushedSequenceIdForTheRegion =</span>
+<span class="source-line-no">2890</span><span id="line-2890">          wal.startCacheFlush(encodedRegionName, flushedFamilyNamesToSeq);</span>
+<span class="source-line-no">2891</span><span id="line-2891">        if (earliestUnflushedSequenceIdForTheRegion == null) {</span>
+<span class="source-line-no">2892</span><span id="line-2892">          // This should never happen. This is how startCacheFlush signals flush cannot proceed.</span>
+<span class="source-line-no">2893</span><span id="line-2893">          String msg = this.getRegionInfo().getEncodedName() + " flush aborted; WAL closing.";</span>
+<span class="source-line-no">2894</span><span id="line-2894">          status.setStatus(msg);</span>
+<span class="source-line-no">2895</span><span id="line-2895">          return new PrepareFlushResult(</span>
+<span class="source-line-no">2896</span><span id="line-2896">            new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH, msg, false), myseqid);</span>
+<span class="source-line-no">2897</span><span id="line-2897">        }</span>
+<span class="source-line-no">2898</span><span id="line-2898">        flushOpSeqId = getNextSequenceId(wal);</span>
+<span class="source-line-no">2899</span><span id="line-2899">        // Back up 1, minus 1 from oldest sequence id in memstore to get last 'flushed' edit</span>
+<span class="source-line-no">2900</span><span id="line-2900">        flushedSeqId = earliestUnflushedSequenceIdForTheRegion.longValue() == HConstants.NO_SEQNUM</span>
+<span class="source-line-no">2901</span><span id="line-2901">          ? flushOpSeqId</span>
+<span class="source-line-no">2902</span><span id="line-2902">          : earliestUnflushedSequenceIdForTheRegion.longValue() - 1;</span>
+<span class="source-line-no">2903</span><span id="line-2903">      } else {</span>
+<span class="source-line-no">2904</span><span id="line-2904">        // use the provided sequence Id as WAL is not being used for this flush.</span>
+<span class="source-line-no">2905</span><span id="line-2905">        flushedSeqId = flushOpSeqId = myseqid;</span>
+<span class="source-line-no">2906</span><span id="line-2906">      }</span>
+<span class="source-line-no">2907</span><span id="line-2907"></span>
+<span class="source-line-no">2908</span><span id="line-2908">      for (HStore s : storesToFlush) {</span>
+<span class="source-line-no">2909</span><span id="line-2909">        storeFlushCtxs.put(s.getColumnFamilyDescriptor().getName(),</span>
+<span class="source-line-no">2910</span><span id="line-2910">          s.createFlushContext(flushOpSeqId, tracker));</span>
+<span class="source-line-no">2911</span><span id="line-2911">        // for writing stores to WAL</span>
+<span class="source-line-no">2912</span><span id="line-2912">        committedFiles.put(s.getColumnFamilyDescriptor().getName(), null);</span>
+<span class="source-line-no">2913</span><span id="line-2913">      }</span>
+<span class="source-line-no">2914</span><span id="line-2914"></span>
+<span class="source-line-no">2915</span><span id="line-2915">      // write the snapshot start to WAL</span>
+<span class="source-line-no">2916</span><span id="line-2916">      if (wal != null &amp;&amp; !writestate.readOnly) {</span>
+<span class="source-line-no">2917</span><span id="line-2917">        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.START_FLUSH,</span>
+<span class="source-line-no">2918</span><span id="line-2918">          getRegionInfo(), flushOpSeqId, committedFiles);</span>
+<span class="source-line-no">2919</span><span id="line-2919">        // No sync. Sync is below where no updates lock and we do FlushAction.COMMIT_FLUSH</span>
+<span class="source-line-no">2920</span><span id="line-2920">        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false,</span>
+<span class="source-line-no">2921</span><span id="line-2921">          mvcc, regionReplicationSink.orElse(null));</span>
+<span class="source-line-no">2922</span><span id="line-2922">      }</span>
+<span class="source-line-no">2923</span><span id="line-2923"></span>
+<span class="source-line-no">2924</span><span id="line-2924">      // Prepare flush (take a snapshot)</span>
+<span class="source-line-no">2925</span><span id="line-2925">      storeFlushCtxs.forEach((name, flush) -&gt; {</span>
+<span class="source-line-no">2926</span><span id="line-2926">        MemStoreSize snapshotSize = flush.prepare();</span>
+<span class="source-line-no">2927</span><span id="line-2927">        totalSizeOfFlushableStores.incMemStoreSize(snapshotSize);</span>
+<span class="source-line-no">2928</span><span id="line-2928">        storeFlushableSize.put(name, snapshotSize);</span>
+<span class="source-line-no">2929</span><span id="line-2929">      });</span>
+<span class="source-line-no">2930</span><span id="line-2930">    } catch (IOException ex) {</span>
+<span class="source-line-no">2931</span><span id="line-2931">      doAbortFlushToWAL(wal, flushOpSeqId, committedFiles);</span>
+<span class="source-line-no">2932</span><span id="line-2932">      throw ex;</span>
+<span class="source-line-no">2933</span><span id="line-2933">    } finally {</span>
+<span class="source-line-no">2934</span><span id="line-2934">      this.updatesLock.writeLock().unlock();</span>
+<span class="source-line-no">2935</span><span id="line-2935">    }</span>
+<span class="source-line-no">2936</span><span id="line-2936">    String s = "Finished memstore snapshotting " + this + ", syncing WAL and waiting on mvcc, "</span>
+<span class="source-line-no">2937</span><span id="line-2937">      + "flushsize=" + totalSizeOfFlushableStores;</span>
+<span class="source-line-no">2938</span><span id="line-2938">    status.setStatus(s);</span>
+<span class="source-line-no">2939</span><span id="line-2939">    doSyncOfUnflushedWALChanges(wal, getRegionInfo());</span>
+<span class="source-line-no">2940</span><span id="line-2940">    return new PrepareFlushResult(storeFlushCtxs, committedFiles, storeFlushableSize, startTime,</span>
+<span class="source-line-no">2941</span><span id="line-2941">      flushOpSeqId, flushedSeqId, totalSizeOfFlushableStores);</span>
+<span class="source-line-no">2942</span><span id="line-2942">  }</span>
+<span class="source-line-no">2943</span><span id="line-2943"></span>
+<span class="source-line-no">2944</span><span id="line-2944">  /**</span>
+<span class="source-line-no">2945</span><span id="line-2945">   * Utility method broken out of internalPrepareFlushCache so that method is smaller.</span>
+<span class="source-line-no">2946</span><span id="line-2946">   */</span>
+<span class="source-line-no">2947</span><span id="line-2947">  private void logFatLineOnFlush(Collection&lt;HStore&gt; storesToFlush, long sequenceId) {</span>
+<span class="source-line-no">2948</span><span id="line-2948">    if (!LOG.isInfoEnabled()) {</span>
+<span class="source-line-no">2949</span><span id="line-2949">      return;</span>
+<span class="source-line-no">2950</span><span id="line-2950">    }</span>
+<span class="source-line-no">2951</span><span id="line-2951">    // Log a fat line detailing what is being flushed.</span>
+<span class="source-line-no">2952</span><span id="line-2952">    StringBuilder perCfExtras = null;</span>
+<span class="source-line-no">2953</span><span id="line-2953">    if (!isAllFamilies(storesToFlush)) {</span>
+<span class="source-line-no">2954</span><span id="line-2954">      perCfExtras = new StringBuilder();</span>
+<span class="source-line-no">2955</span><span id="line-2955">      for (HStore store : storesToFlush) {</span>
+<span class="source-line-no">2956</span><span id="line-2956">        MemStoreSize mss = store.getFlushableSize();</span>
+<span class="source-line-no">2957</span><span id="line-2957">        perCfExtras.append("; ").append(store.getColumnFamilyName());</span>
+<span class="source-line-no">2958</span><span id="line-2958">        perCfExtras.append("={dataSize=").append(StringUtils.byteDesc(mss.getDataSize()));</span>
+<span class="source-line-no">2959</span><span id="line-2959">        perCfExtras.append(", heapSize=").append(StringUtils.byteDesc(mss.getHeapSize()));</span>
+<span class="source-line-no">2960</span><span id="line-2960">        perCfExtras.append(", offHeapSize=").append(StringUtils.byteDesc(mss.getOffHeapSize()));</span>
+<span class="source-line-no">2961</span><span id="line-2961">        perCfExtras.append("}");</span>
+<span class="source-line-no">2962</span><span id="line-2962">      }</span>
+<span class="source-line-no">2963</span><span id="line-2963">    }</span>
+<span class="source-line-no">2964</span><span id="line-2964">    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();</span>
+<span class="source-line-no">2965</span><span id="line-2965">    LOG.info("Flushing " + this.getRegionInfo().getEncodedName() + " " + storesToFlush.size() + "/"</span>
+<span class="source-line-no">2966</span><span id="line-2966">      + stores.size() + " column families," + " dataSize=" + StringUtils.byteDesc(mss.getDataSize())</span>
+<span class="source-line-no">2967</span><span id="line-2967">      + " heapSize=" + StringUtils.byteDesc(mss.getHeapSize())</span>
+<span class="source-line-no">2968</span><span id="line-2968">      + ((perCfExtras != null &amp;&amp; perCfExtras.length() &gt; 0) ? perCfExtras.toString() : "")</span>
+<span class="source-line-no">2969</span><span id="line-2969">      + ((wal != null) ? "" : "; WAL is null, using passed sequenceid=" + sequenceId));</span>
+<span class="source-line-no">2970</span><span id="line-2970">  }</span>
+<span class="source-line-no">2971</span><span id="line-2971"></span>
+<span class="source-line-no">2972</span><span id="line-2972">  private void doAbortFlushToWAL(final WAL wal, final long flushOpSeqId,</span>
+<span class="source-line-no">2973</span><span id="line-2973">    final Map&lt;byte[], List&lt;Path&gt;&gt; committedFiles) {</span>
+<span class="source-line-no">2974</span><span id="line-2974">    if (wal == null) return;</span>
+<span class="source-line-no">2975</span><span id="line-2975">    try {</span>
+<span class="source-line-no">2976</span><span id="line-2976">      FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,</span>
+<span class="source-line-no">2977</span><span id="line-2977">        getRegionInfo(), flushOpSeqId, committedFiles);</span>
+<span class="source-line-no">2978</span><span id="line-2978">      WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, false, mvcc,</span>
+<span class="source-line-no">2979</span><span id="line-2979">        null);</span>
+<span class="source-line-no">2980</span><span id="line-2980">    } catch (Throwable t) {</span>
+<span class="source-line-no">2981</span><span id="line-2981">      LOG.warn("Received unexpected exception trying to write ABORT_FLUSH marker to WAL: {} in "</span>
+<span class="source-line-no">2982</span><span id="line-2982">        + " region {}", StringUtils.stringifyException(t), this);</span>
+<span class="source-line-no">2983</span><span id="line-2983">      // ignore this since we will be aborting the RS with DSE.</span>
+<span class="source-line-no">2984</span><span id="line-2984">    }</span>
+<span class="source-line-no">2985</span><span id="line-2985">    // we have called wal.startCacheFlush(), now we have to abort it</span>
+<span class="source-line-no">2986</span><span id="line-2986">    wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());</span>
+<span class="source-line-no">2987</span><span id="line-2987">  }</span>
+<span class="source-line-no">2988</span><span id="line-2988"></span>
+<span class="source-line-no">2989</span><span id="line-2989">  /**</span>
+<span class="source-line-no">2990</span><span id="line-2990">   * Sync unflushed WAL changes. See HBASE-8208 for details</span>
+<span class="source-line-no">2991</span><span id="line-2991">   */</span>
+<span class="source-line-no">2992</span><span id="line-2992">  private static void doSyncOfUnflushedWALChanges(final WAL wal, final RegionInfo hri)</span>
+<span class="source-line-no">2993</span><span id="line-2993">    throws IOException {</span>
+<span class="source-line-no">2994</span><span id="line-2994">    if (wal == null) {</span>
+<span class="source-line-no">2995</span><span id="line-2995">      return;</span>
+<span class="source-line-no">2996</span><span id="line-2996">    }</span>
+<span class="source-line-no">2997</span><span id="line-2997">    try {</span>
+<span class="source-line-no">2998</span><span id="line-2998">      wal.sync(); // ensure that flush marker is sync'ed</span>
+<span class="source-line-no">2999</span><span id="line-2999">    } catch (IOException ioe) {</span>
+<span class="source-line-no">3000</span><span id="line-3000">      wal.abortCacheFlush(hri.getEncodedNameAsBytes());</span>
+<span class="source-line-no">3001</span><span id="line-3001">      throw ioe;</span>
+<span class="source-line-no">3002</span><span id="line-3002">    }</span>
+<span class="source-line-no">3003</span><span id="line-3003">  }</span>
+<span class="source-line-no">3004</span><span id="line-3004"></span>
+<span class="source-line-no">3005</span><span id="line-3005">  /** Returns True if passed Set is all families in the region. */</span>
+<span class="source-line-no">3006</span><span id="line-3006">  private boolean isAllFamilies(Collection&lt;HStore&gt; families) {</span>
+<span class="source-line-no">3007</span><span id="line-3007">    return families == null || this.stores.size() == families.size();</span>
+<span class="source-line-no">3008</span><span id="line-3008">  }</span>
+<span class="source-line-no">3009</span><span id="line-3009"></span>
+<span class="source-line-no">3010</span><span id="line-3010">  /**</span>
+<span class="source-line-no">3011</span><span id="line-3011">   * This method is only used when we flush but the memstore is empty,if writeFlushWalMarker is</span>
+<span class="source-line-no">3012</span><span id="line-3012">   * true,we write the {@link FlushAction#CANNOT_FLUSH} flush marker to WAL when the memstore is</span>
+<span class="source-line-no">3013</span><span id="line-3013">   * empty. Ignores exceptions from WAL. Returns whether the write succeeded.</span>
+<span class="source-line-no">3014</span><span id="line-3014">   * @return whether WAL write was successful</span>
+<span class="source-line-no">3015</span><span id="line-3015">   */</span>
+<span class="source-line-no">3016</span><span id="line-3016">  private boolean writeCanNotFlushMarkerToWAL(WriteEntry flushOpSeqIdMVCCEntry, WAL wal,</span>
+<span class="source-line-no">3017</span><span id="line-3017">    boolean writeFlushWalMarker) {</span>
+<span class="source-line-no">3018</span><span id="line-3018">    FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.CANNOT_FLUSH, getRegionInfo(),</span>
+<span class="source-line-no">3019</span><span id="line-3019">      -1, new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR));</span>
+<span class="source-line-no">3020</span><span id="line-3020">    RegionReplicationSink sink = regionReplicationSink.orElse(null);</span>
+<span class="source-line-no">3021</span><span id="line-3021"></span>
+<span class="source-line-no">3022</span><span id="line-3022">    if (sink != null &amp;&amp; !writeFlushWalMarker) {</span>
+<span class="source-line-no">3023</span><span id="line-3023">      /**</span>
+<span class="source-line-no">3024</span><span id="line-3024">       * Here for replication to secondary region replica could use {@link FlushAction#CANNOT_FLUSH}</span>
+<span class="source-line-no">3025</span><span id="line-3025">       * to recover when writeFlushWalMarker is false, we create {@link WALEdit} for</span>
+<span class="source-line-no">3026</span><span id="line-3026">       * {@link FlushDescriptor} and attach the {@link RegionReplicationSink#add} to the</span>
+<span class="source-line-no">3027</span><span id="line-3027">       * flushOpSeqIdMVCCEntry,see HBASE-26960 for more details.</span>
+<span class="source-line-no">3028</span><span id="line-3028">       */</span>
+<span class="source-line-no">3029</span><span id="line-3029">      this.attachRegionReplicationToFlushOpSeqIdMVCCEntry(flushOpSeqIdMVCCEntry, desc, sink);</span>
+<span class="source-line-no">3030</span><span id="line-3030">      return false;</span>
+<span class="source-line-no">3031</span><span id="line-3031">    }</span>
+<span class="source-line-no">3032</span><span id="line-3032"></span>
+<span class="source-line-no">3033</span><span id="line-3033">    if (writeFlushWalMarker &amp;&amp; wal != null &amp;&amp; !writestate.readOnly) {</span>
+<span class="source-line-no">3034</span><span id="line-3034">      try {</span>
+<span class="source-line-no">3035</span><span id="line-3035">        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true, mvcc,</span>
+<span class="source-line-no">3036</span><span id="line-3036">          sink);</span>
+<span class="source-line-no">3037</span><span id="line-3037">        return true;</span>
+<span class="source-line-no">3038</span><span id="line-3038">      } catch (IOException e) {</span>
+<span class="source-line-no">3039</span><span id="line-3039">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">3040</span><span id="line-3040">          + "Received exception while trying to write the flush request to wal", e);</span>
+<span class="source-line-no">3041</span><span id="line-3041">      }</span>
+<span class="source-line-no">3042</span><span id="line-3042">    }</span>
+<span class="source-line-no">3043</span><span id="line-3043">    return false;</span>
+<span class="source-line-no">3044</span><span id="line-3044">  }</span>
+<span class="source-line-no">3045</span><span id="line-3045"></span>
+<span class="source-line-no">3046</span><span id="line-3046">  /**</span>
+<span class="source-line-no">3047</span><span id="line-3047">   * Create {@link WALEdit} for {@link FlushDescriptor} and attach {@link RegionReplicationSink#add}</span>
+<span class="source-line-no">3048</span><span id="line-3048">   * to the flushOpSeqIdMVCCEntry.</span>
+<span class="source-line-no">3049</span><span id="line-3049">   */</span>
+<span class="source-line-no">3050</span><span id="line-3050">  private void attachRegionReplicationToFlushOpSeqIdMVCCEntry(WriteEntry flushOpSeqIdMVCCEntry,</span>
+<span class="source-line-no">3051</span><span id="line-3051">    FlushDescriptor desc, RegionReplicationSink sink) {</span>
+<span class="source-line-no">3052</span><span id="line-3052">    assert !flushOpSeqIdMVCCEntry.getCompletionAction().isPresent();</span>
+<span class="source-line-no">3053</span><span id="line-3053">    WALEdit flushMarkerWALEdit = WALEdit.createFlushWALEdit(getRegionInfo(), desc);</span>
+<span class="source-line-no">3054</span><span id="line-3054">    WALKeyImpl walKey =</span>
+<span class="source-line-no">3055</span><span id="line-3055">      WALUtil.createWALKey(getRegionInfo(), mvcc, this.getReplicationScope(), null);</span>
+<span class="source-line-no">3056</span><span id="line-3056">    walKey.setWriteEntry(flushOpSeqIdMVCCEntry);</span>
+<span class="source-line-no">3057</span><span id="line-3057">    /**</span>
+<span class="source-line-no">3058</span><span id="line-3058">     * Here the {@link ServerCall} is null for {@link RegionReplicationSink#add} because the</span>
+<span class="source-line-no">3059</span><span id="line-3059">     * flushMarkerWALEdit is created by ourselves, not from rpc.</span>
+<span class="source-line-no">3060</span><span id="line-3060">     */</span>
+<span class="source-line-no">3061</span><span id="line-3061">    flushOpSeqIdMVCCEntry.attachCompletionAction(() -&gt; sink.add(walKey, flushMarkerWALEdit, null));</span>
+<span class="source-line-no">3062</span><span id="line-3062">  }</span>
+<span class="source-line-no">3063</span><span id="line-3063"></span>
+<span class="source-line-no">3064</span><span id="line-3064">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",</span>
+<span class="source-line-no">3065</span><span id="line-3065">      justification = "Intentional; notify is about completed flush")</span>
+<span class="source-line-no">3066</span><span id="line-3066">  FlushResultImpl internalFlushCacheAndCommit(WAL wal, MonitoredTask status,</span>
+<span class="source-line-no">3067</span><span id="line-3067">    PrepareFlushResult prepareResult, Collection&lt;HStore&gt; storesToFlush) throws IOException {</span>
+<span class="source-line-no">3068</span><span id="line-3068">    // prepare flush context is carried via PrepareFlushResult</span>
+<span class="source-line-no">3069</span><span id="line-3069">    TreeMap&lt;byte[], StoreFlushContext&gt; storeFlushCtxs = prepareResult.storeFlushCtxs;</span>
+<span class="source-line-no">3070</span><span id="line-3070">    TreeMap&lt;byte[], List&lt;Path&gt;&gt; committedFiles = prepareResult.committedFiles;</span>
+<span class="source-line-no">3071</span><span id="line-3071">    long startTime = prepareResult.startTime;</span>
+<span class="source-line-no">3072</span><span id="line-3072">    long flushOpSeqId = prepareResult.flushOpSeqId;</span>
+<span class="source-line-no">3073</span><span id="line-3073">    long flushedSeqId = prepareResult.flushedSeqId;</span>
+<span class="source-line-no">3074</span><span id="line-3074"></span>
+<span class="source-line-no">3075</span><span id="line-3075">    String s = "Flushing stores of " + this;</span>
+<span class="source-line-no">3076</span><span id="line-3076">    status.setStatus(s);</span>
+<span class="source-line-no">3077</span><span id="line-3077">    if (LOG.isTraceEnabled()) LOG.trace(s);</span>
+<span class="source-line-no">3078</span><span id="line-3078"></span>
+<span class="source-line-no">3079</span><span id="line-3079">    // Any failure from here on out will be catastrophic requiring server</span>
+<span class="source-line-no">3080</span><span id="line-3080">    // restart so wal content can be replayed and put back into the memstore.</span>
+<span class="source-line-no">3081</span><span id="line-3081">    // Otherwise, the snapshot content while backed up in the wal, it will not</span>
+<span class="source-line-no">3082</span><span id="line-3082">    // be part of the current running servers state.</span>
+<span class="source-line-no">3083</span><span id="line-3083">    boolean compactionRequested = false;</span>
+<span class="source-line-no">3084</span><span id="line-3084">    long flushedOutputFileSize = 0;</span>
+<span class="source-line-no">3085</span><span id="line-3085">    try {</span>
+<span class="source-line-no">3086</span><span id="line-3086">      // A. Flush memstore to all the HStores.</span>
+<span class="source-line-no">3087</span><span id="line-3087">      // Keep running vector of all store files that includes both old and the</span>
+<span class="source-line-no">3088</span><span id="line-3088">      // just-made new flush store file. The new flushed file is still in the</span>
+<span class="source-line-no">3089</span><span id="line-3089">      // tmp directory.</span>
+<span class="source-line-no">3090</span><span id="line-3090"></span>
+<span class="source-line-no">3091</span><span id="line-3091">      for (StoreFlushContext flush : storeFlushCtxs.values()) {</span>
+<span class="source-line-no">3092</span><span id="line-3092">        flush.flushCache(status);</span>
 <span class="source-line-no">3093</span><span id="line-3093">      }</span>
-<span class="source-line-no">3094</span><span id="line-3094">      DroppedSnapshotException dse = new DroppedSnapshotException(</span>
-<span class="source-line-no">3095</span><span id="line-3095">        "region: " + Bytes.toStringBinary(getRegionInfo().getRegionName()), t);</span>
-<span class="source-line-no">3096</span><span id="line-3096">      status.abort("Flush failed: " + StringUtils.stringifyException(t));</span>
-<span class="source-line-no">3097</span><span id="line-3097"></span>
-<span class="source-line-no">3098</span><span id="line-3098">      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.</span>
-<span class="source-line-no">3099</span><span id="line-3099">      // However, since we may have the region read lock, we cannot call close(true) here since</span>
-<span class="source-line-no">3100</span><span id="line-3100">      // we cannot promote to a write lock. Instead we are setting closing so that all other region</span>
-<span class="source-line-no">3101</span><span id="line-3101">      // operations except for close will be rejected.</span>
-<span class="source-line-no">3102</span><span id="line-3102">      this.closing.set(true);</span>
-<span class="source-line-no">3103</span><span id="line-3103"></span>
-<span class="source-line-no">3104</span><span id="line-3104">      if (rsServices != null) {</span>
-<span class="source-line-no">3105</span><span id="line-3105">        // This is a safeguard against the case where the caller fails to explicitly handle aborting</span>
-<span class="source-line-no">3106</span><span id="line-3106">        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);</span>
-<span class="source-line-no">3107</span><span id="line-3107">      }</span>
-<span class="source-line-no">3108</span><span id="line-3108"></span>
-<span class="source-line-no">3109</span><span id="line-3109">      throw dse;</span>
-<span class="source-line-no">3110</span><span id="line-3110">    }</span>
-<span class="source-line-no">3111</span><span id="line-3111"></span>
-<span class="source-line-no">3112</span><span id="line-3112">    // If we get to here, the HStores have been written.</span>
-<span class="source-line-no">3113</span><span id="line-3113">    if (wal != null) {</span>
-<span class="source-line-no">3114</span><span id="line-3114">      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes(), flushedSeqId);</span>
-<span class="source-line-no">3115</span><span id="line-3115">    }</span>
-<span class="source-line-no">3116</span><span id="line-3116"></span>
-<span class="source-line-no">3117</span><span id="line-3117">    // Record latest flush time</span>
-<span class="source-line-no">3118</span><span id="line-3118">    for (HStore store : storesToFlush) {</span>
-<span class="source-line-no">3119</span><span id="line-3119">      this.lastStoreFlushTimeMap.put(store, startTime);</span>
-<span class="source-line-no">3120</span><span id="line-3120">    }</span>
-<span class="source-line-no">3121</span><span id="line-3121"></span>
-<span class="source-line-no">3122</span><span id="line-3122">    this.maxFlushedSeqId = flushedSeqId;</span>
-<span class="source-line-no">3123</span><span id="line-3123">    this.lastFlushOpSeqId = flushOpSeqId;</span>
-<span class="source-line-no">3124</span><span id="line-3124"></span>
-<span class="source-line-no">3125</span><span id="line-3125">    // C. Finally notify anyone waiting on memstore to clear:</span>
-<span class="source-line-no">3126</span><span id="line-3126">    // e.g. checkResources().</span>
-<span class="source-line-no">3127</span><span id="line-3127">    synchronized (this) {</span>
-<span class="source-line-no">3128</span><span id="line-3128">      notifyAll(); // FindBugs NN_NAKED_NOTIFY</span>
-<span class="source-line-no">3129</span><span id="line-3129">    }</span>
-<span class="source-line-no">3130</span><span id="line-3130"></span>
-<span class="source-line-no">3131</span><span id="line-3131">    long time = EnvironmentEdgeManager.currentTime() - startTime;</span>
-<span class="source-line-no">3132</span><span id="line-3132">    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();</span>
-<span class="source-line-no">3133</span><span id="line-3133">    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();</span>
-<span class="source-line-no">3134</span><span id="line-3134">    String msg = "Finished flush of" + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/"</span>
-<span class="source-line-no">3135</span><span id="line-3135">      + mss.getDataSize() + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/"</span>
-<span class="source-line-no">3136</span><span id="line-3136">      + mss.getHeapSize() + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/"</span>
-<span class="source-line-no">3137</span><span id="line-3137">      + memstoresize + " for " + this.getRegionInfo().getEncodedName() + " in " + time</span>
-<span class="source-line-no">3138</span><span id="line-3138">      + "ms, sequenceid=" + flushOpSeqId + ", compaction requested=" + compactionRequested</span>
-<span class="source-line-no">3139</span><span id="line-3139">      + ((wal == null) ? "; wal=null" : "");</span>
-<span class="source-line-no">3140</span><span id="line-3140">    LOG.info(msg);</span>
-<span class="source-line-no">3141</span><span id="line-3141">    status.setStatus(msg);</span>
-<span class="source-line-no">3142</span><span id="line-3142"></span>
-<span class="source-line-no">3143</span><span id="line-3143">    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {</span>
-<span class="source-line-no">3144</span><span id="line-3144">      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),</span>
-<span class="source-line-no">3145</span><span id="line-3145">        time, mss.getDataSize(), flushedOutputFileSize);</span>
-<span class="source-line-no">3146</span><span id="line-3146">    }</span>
-<span class="source-line-no">3147</span><span id="line-3147"></span>
-<span class="source-line-no">3148</span><span id="line-3148">    return new FlushResultImpl(compactionRequested</span>
-<span class="source-line-no">3149</span><span id="line-3149">      ? FlushResult.Result.FLUSHED_COMPACTION_NEEDED</span>
-<span class="source-line-no">3150</span><span id="line-3150">      : FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);</span>
-<span class="source-line-no">3151</span><span id="line-3151">  }</span>
-<span class="source-line-no">3152</span><span id="line-3152"></span>
-<span class="source-line-no">3153</span><span id="line-3153">  /**</span>
-<span class="source-line-no">3154</span><span id="line-3154">   * Method to safely get the next sequence number.</span>
-<span class="source-line-no">3155</span><span id="line-3155">   * @return Next sequence number unassociated with any actual edit.</span>
-<span class="source-line-no">3156</span><span id="line-3156">   */</span>
-<span class="source-line-no">3157</span><span id="line-3157">  protected long getNextSequenceId(final WAL wal) throws IOException {</span>
-<span class="source-line-no">3158</span><span id="line-3158">    WriteEntry we = mvcc.begin();</span>
-<span class="source-line-no">3159</span><span id="line-3159">    mvcc.completeAndWait(we);</span>
-<span class="source-line-no">3160</span><span id="line-3160">    return we.getWriteNumber();</span>
-<span class="source-line-no">3161</span><span id="line-3161">  }</span>
-<span class="source-line-no">3162</span><span id="line-3162"></span>
-<span class="source-line-no">3163</span><span id="line-3163">  //////////////////////////////////////////////////////////////////////////////</span>
-<span class="source-line-no">3164</span><span id="line-3164">  // get() methods for client use.</span>
-<span class="source-line-no">3165</span><span id="line-3165">  //////////////////////////////////////////////////////////////////////////////</span>
+<span class="source-line-no">3094</span><span id="line-3094"></span>
+<span class="source-line-no">3095</span><span id="line-3095">      // Switch snapshot (in memstore) -&gt; new hfile (thus causing</span>
+<span class="source-line-no">3096</span><span id="line-3096">      // all the store scanners to reset/reseek).</span>
+<span class="source-line-no">3097</span><span id="line-3097">      for (Map.Entry&lt;byte[], StoreFlushContext&gt; flushEntry : storeFlushCtxs.entrySet()) {</span>
+<span class="source-line-no">3098</span><span id="line-3098">        StoreFlushContext sfc = flushEntry.getValue();</span>
+<span class="source-line-no">3099</span><span id="line-3099">        boolean needsCompaction = sfc.commit(status);</span>
+<span class="source-line-no">3100</span><span id="line-3100">        if (needsCompaction) {</span>
+<span class="source-line-no">3101</span><span id="line-3101">          compactionRequested = true;</span>
+<span class="source-line-no">3102</span><span id="line-3102">        }</span>
+<span class="source-line-no">3103</span><span id="line-3103">        byte[] storeName = flushEntry.getKey();</span>
+<span class="source-line-no">3104</span><span id="line-3104">        List&lt;Path&gt; storeCommittedFiles = sfc.getCommittedFiles();</span>
+<span class="source-line-no">3105</span><span id="line-3105">        committedFiles.put(storeName, storeCommittedFiles);</span>
+<span class="source-line-no">3106</span><span id="line-3106">        // Flush committed no files, indicating flush is empty or flush was canceled</span>
+<span class="source-line-no">3107</span><span id="line-3107">        if (storeCommittedFiles == null || storeCommittedFiles.isEmpty()) {</span>
+<span class="source-line-no">3108</span><span id="line-3108">          MemStoreSize storeFlushableSize = prepareResult.storeFlushableSize.get(storeName);</span>
+<span class="source-line-no">3109</span><span id="line-3109">          prepareResult.totalFlushableSize.decMemStoreSize(storeFlushableSize);</span>
+<span class="source-line-no">3110</span><span id="line-3110">        }</span>
+<span class="source-line-no">3111</span><span id="line-3111">        flushedOutputFileSize += sfc.getOutputFileSize();</span>
+<span class="source-line-no">3112</span><span id="line-3112">      }</span>
+<span class="source-line-no">3113</span><span id="line-3113">      storeFlushCtxs.clear();</span>
+<span class="source-line-no">3114</span><span id="line-3114"></span>
+<span class="source-line-no">3115</span><span id="line-3115">      // Set down the memstore size by amount of flush.</span>
+<span class="source-line-no">3116</span><span id="line-3116">      MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();</span>
+<span class="source-line-no">3117</span><span id="line-3117">      this.decrMemStoreSize(mss);</span>
+<span class="source-line-no">3118</span><span id="line-3118"></span>
+<span class="source-line-no">3119</span><span id="line-3119">      // Increase the size of this Region for the purposes of quota. Noop if quotas are disabled.</span>
+<span class="source-line-no">3120</span><span id="line-3120">      // During startup, quota manager may not be initialized yet.</span>
+<span class="source-line-no">3121</span><span id="line-3121">      if (rsServices != null) {</span>
+<span class="source-line-no">3122</span><span id="line-3122">        RegionServerSpaceQuotaManager quotaManager = rsServices.getRegionServerSpaceQuotaManager();</span>
+<span class="source-line-no">3123</span><span id="line-3123">        if (quotaManager != null) {</span>
+<span class="source-line-no">3124</span><span id="line-3124">          quotaManager.getRegionSizeStore().incrementRegionSize(this.getRegionInfo(),</span>
+<span class="source-line-no">3125</span><span id="line-3125">            flushedOutputFileSize);</span>
+<span class="source-line-no">3126</span><span id="line-3126">        }</span>
+<span class="source-line-no">3127</span><span id="line-3127">      }</span>
+<span class="source-line-no">3128</span><span id="line-3128"></span>
+<span class="source-line-no">3129</span><span id="line-3129">      if (wal != null) {</span>
+<span class="source-line-no">3130</span><span id="line-3130">        // write flush marker to WAL. If fail, we should throw DroppedSnapshotException</span>
+<span class="source-line-no">3131</span><span id="line-3131">        FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.COMMIT_FLUSH,</span>
+<span class="source-line-no">3132</span><span id="line-3132">          getRegionInfo(), flushOpSeqId, committedFiles);</span>
+<span class="source-line-no">3133</span><span id="line-3133">        WALUtil.writeFlushMarker(wal, this.getReplicationScope(), getRegionInfo(), desc, true, mvcc,</span>
+<span class="source-line-no">3134</span><span id="line-3134">          regionReplicationSink.orElse(null));</span>
+<span class="source-line-no">3135</span><span id="line-3135">      }</span>
+<span class="source-line-no">3136</span><span id="line-3136">    } catch (Throwable t) {</span>
+<span class="source-line-no">3137</span><span id="line-3137">      // An exception here means that the snapshot was not persisted.</span>
+<span class="source-line-no">3138</span><span id="line-3138">      // The wal needs to be replayed so its content is restored to memstore.</span>
+<span class="source-line-no">3139</span><span id="line-3139">      // Currently, only a server restart will do this.</span>
+<span class="source-line-no">3140</span><span id="line-3140">      // We used to only catch IOEs but its possible that we'd get other</span>
+<span class="source-line-no">3141</span><span id="line-3141">      // exceptions -- e.g. HBASE-659 was about an NPE -- so now we catch</span>
+<span class="source-line-no">3142</span><span id="line-3142">      // all and sundry.</span>
+<span class="source-line-no">3143</span><span id="line-3143">      if (wal != null) {</span>
+<span class="source-line-no">3144</span><span id="line-3144">        try {</span>
+<span class="source-line-no">3145</span><span id="line-3145">          FlushDescriptor desc = ProtobufUtil.toFlushDescriptor(FlushAction.ABORT_FLUSH,</span>
+<span class="source-line-no">3146</span><span id="line-3146">            getRegionInfo(), flushOpSeqId, committedFiles);</span>
+<span class="source-line-no">3147</span><span id="line-3147">          WALUtil.writeFlushMarker(wal, this.replicationScope, getRegionInfo(), desc, false, mvcc,</span>
+<span class="source-line-no">3148</span><span id="line-3148">            null);</span>
+<span class="source-line-no">3149</span><span id="line-3149">        } catch (Throwable ex) {</span>
+<span class="source-line-no">3150</span><span id="line-3150">          LOG.warn(</span>
+<span class="source-line-no">3151</span><span id="line-3151">            getRegionInfo().getEncodedName() + " : " + "failed writing ABORT_FLUSH marker to WAL",</span>
+<span class="source-line-no">3152</span><span id="line-3152">            ex);</span>
+<span class="source-line-no">3153</span><span id="line-3153">          // ignore this since we will be aborting the RS with DSE.</span>
+<span class="source-line-no">3154</span><span id="line-3154">        }</span>
+<span class="source-line-no">3155</span><span id="line-3155">        wal.abortCacheFlush(this.getRegionInfo().getEncodedNameAsBytes());</span>
+<span class="source-line-no">3156</span><span id="line-3156">      }</span>
+<span class="source-line-no">3157</span><span id="line-3157">      DroppedSnapshotException dse = new DroppedSnapshotException(</span>
+<span class="source-line-no">3158</span><span id="line-3158">        "region: " + Bytes.toStringBinary(getRegionInfo().getRegionName()), t);</span>
+<span class="source-line-no">3159</span><span id="line-3159">      status.abort("Flush failed: " + StringUtils.stringifyException(t));</span>
+<span class="source-line-no">3160</span><span id="line-3160"></span>
+<span class="source-line-no">3161</span><span id="line-3161">      // Callers for flushcache() should catch DroppedSnapshotException and abort the region server.</span>
+<span class="source-line-no">3162</span><span id="line-3162">      // However, since we may have the region read lock, we cannot call close(true) here since</span>
+<span class="source-line-no">3163</span><span id="line-3163">      // we cannot promote to a write lock. Instead we are setting closing so that all other region</span>
+<span class="source-line-no">3164</span><span id="line-3164">      // operations except for close will be rejected.</span>
+<span class="source-line-no">3165</span><span id="line-3165">      this.closing.set(true);</span>
 <span class="source-line-no">3166</span><span id="line-3166"></span>
-<span class="source-line-no">3167</span><span id="line-3167">  @Override</span>
-<span class="source-line-no">3168</span><span id="line-3168">  public RegionScannerImpl getScanner(Scan scan) throws IOException {</span>
-<span class="source-line-no">3169</span><span id="line-3169">    return getScanner(scan, null);</span>
-<span class="source-line-no">3170</span><span id="line-3170">  }</span>
+<span class="source-line-no">3167</span><span id="line-3167">      if (rsServices != null) {</span>
+<span class="source-line-no">3168</span><span id="line-3168">        // This is a safeguard against the case where the caller fails to explicitly handle aborting</span>
+<span class="source-line-no">3169</span><span id="line-3169">        rsServices.abort("Replay of WAL required. Forcing server shutdown", dse);</span>
+<span class="source-line-no">3170</span><span id="line-3170">      }</span>
 <span class="source-line-no">3171</span><span id="line-3171"></span>
-<span class="source-line-no">3172</span><span id="line-3172">  @Override</span>
-<span class="source-line-no">3173</span><span id="line-3173">  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)</span>
-<span class="source-line-no">3174</span><span id="line-3174">    throws IOException {</span>
-<span class="source-line-no">3175</span><span id="line-3175">    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);</span>
-<span class="source-line-no">3176</span><span id="line-3176">  }</span>
-<span class="source-line-no">3177</span><span id="line-3177"></span>
-<span class="source-line-no">3178</span><span id="line-3178">  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,</span>
-<span class="source-line-no">3179</span><span id="line-3179">    long nonceGroup, long nonce) throws IOException {</span>
-<span class="source-line-no">3180</span><span id="line-3180">    return TraceUtil.trace(() -&gt; {</span>
-<span class="source-line-no">3181</span><span id="line-3181">      startRegionOperation(Operation.SCAN);</span>
-<span class="source-line-no">3182</span><span id="line-3182">      try {</span>
-<span class="source-line-no">3183</span><span id="line-3183">        // Verify families are all valid</span>
-<span class="source-line-no">3184</span><span id="line-3184">        if (!scan.hasFamilies()) {</span>
-<span class="source-line-no">3185</span><span id="line-3185">          // Adding all families to scanner</span>
-<span class="source-line-no">3186</span><span id="line-3186">          for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {</span>
-<span class="source-line-no">3187</span><span id="line-3187">            scan.addFamily(family);</span>
-<span class="source-line-no">3188</span><span id="line-3188">          }</span>
-<span class="source-line-no">3189</span><span id="line-3189">        } else {</span>
-<span class="source-line-no">3190</span><span id="line-3190">          for (byte[] family : scan.getFamilyMap().keySet()) {</span>
-<span class="source-line-no">3191</span><span id="line-3191">            checkFamily(family);</span>
-<span class="source-line-no">3192</span><span id="line-3192">          }</span>
-<span class="source-line-no">3193</span><span id="line-3193">        }</span>
-<span class="source-line-no">3194</span><span id="line-3194">        return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);</span>
-<span class="source-line-no">3195</span><span id="line-3195">      } finally {</span>
-<span class="source-line-no">3196</span><span id="line-3196">        closeRegionOperation(Operation.SCAN);</span>
-<span class="source-line-no">3197</span><span id="line-3197">      }</span>
-<span class="source-line-no">3198</span><span id="line-3198">    }, () -&gt; createRegionSpan("Region.getScanner"));</span>
-<span class="source-line-no">3199</span><span id="line-3199">  }</span>
-<span class="source-line-no">3200</span><span id="line-3200"></span>
-<span class="source-line-no">3201</span><span id="line-3201">  protected RegionScannerImpl instantiateRegionScanner(Scan scan,</span>
-<span class="source-line-no">3202</span><span id="line-3202">    List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {</span>
-<span class="source-line-no">3203</span><span id="line-3203">    if (scan.isReversed()) {</span>
-<span class="source-line-no">3204</span><span id="line-3204">      if (scan.getFilter() != null) {</span>
-<span class="source-line-no">3205</span><span id="line-3205">        scan.getFilter().setReversed(true);</span>
-<span class="source-line-no">3206</span><span id="line-3206">      }</span>
-<span class="source-line-no">3207</span><span id="line-3207">      return new ReversedRegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);</span>
-<span class="source-line-no">3208</span><span id="line-3208">    }</span>
-<span class="source-line-no">3209</span><span id="line-3209">    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);</span>
-<span class="source-line-no">3210</span><span id="line-3210">  }</span>
-<span class="source-line-no">3211</span><span id="line-3211"></span>
-<span class="source-line-no">3212</span><span id="line-3212">  /**</span>
-<span class="source-line-no">3213</span><span id="line-3213">   * Prepare a delete for a row mutation processor</span>
-<span class="source-line-no">3214</span><span id="line-3214">   * @param delete The passed delete is modified by this method. WARNING!</span>
-<span class="source-line-no">3215</span><span id="line-3215">   */</span>
-<span class="source-line-no">3216</span><span id="line-3216">  private void prepareDelete(Delete delete) throws IOException {</span>
-<span class="source-line-no">3217</span><span id="line-3217">    // Check to see if this is a deleteRow insert</span>
-<span class="source-line-no">3218</span><span id="line-3218">    if (delete.getFamilyCellMap().isEmpty()) {</span>
-<span class="source-line-no">3219</span><span id="line-3219">      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {</span>
-<span class="source-line-no">3220</span><span id="line-3220">        // Don't eat the timestamp</span>
-<span class="source-line-no">3221</span><span id="line-3221">        delete.addFamily(family, delete.getTimestamp());</span>
-<span class="source-line-no">3222</span><span id="line-3222">      }</span>
-<span class="source-line-no">3223</span><span id="line-3223">    } else {</span>
-<span class="source-line-no">3224</span><span id="line-3224">      for (byte[] family : delete.getFamilyCellMap().keySet()) {</span>
-<span class="source-line-no">3225</span><span id="line-3225">        if (family == null) {</span>
-<span class="source-line-no">3226</span><span id="line-3226">          throw new NoSuchColumnFamilyException("Empty family is invalid");</span>
-<span class="source-line-no">3227</span><span id="line-3227">        }</span>
-<span class="source-line-no">3228</span><span id="line-3228">        checkFamily(family, delete.getDurability());</span>
-<span class="source-line-no">3229</span><span id="line-3229">      }</span>
-<span class="source-line-no">3230</span><span id="line-3230">    }</span>
-<span class="source-line-no">3231</span><span id="line-3231">  }</span>
-<span class="source-line-no">3232</span><span id="line-3232"></span>
-<span class="source-line-no">3233</span><span id="line-3233">  @Override</span>
-<span class="source-line-no">3234</span><span id="line-3234">  public void delete(Delete delete) throws IOException {</span>
-<span class="source-line-no">3235</span><span id="line-3235">    TraceUtil.trace(() -&gt; {</span>
-<span class="source-line-no">3236</span><span id="line-3236">      checkReadOnly();</span>
-<span class="source-line-no">3237</span><span id="line-3237">      checkResources();</span>
-<span class="source-line-no">3238</span><span id="line-3238">      startRegionOperation(Operation.DELETE);</span>
-<span class="source-line-no">3239</span><span id="line-3239">      try {</span>
-<span class="source-line-no">3240</span><span id="line-3240">        // All edits for the given row (across all column families) must happen atomically.</span>
-<span class="source-line-no">3241</span><span id="line-3241">        return mutate(delete);</span>
-<span class="source-line-no">3242</span><span id="line-3242">      } finally {</span>
-<span class="source-line-no">3243</span><span id="line-3243">        closeRegionOperation(Operation.DELETE);</span>
-<span class="source-line-no">3244</span><span id="line-3244">      }</span>
-<span class="source-line-no">3245</span><span id="line-3245">    }, () -&gt; createRegionSpan("Region.delete"));</span>
-<span class="source-line-no">3246</span><span id="line-3246">  }</span>
-<span class="source-line-no">3247</span><span id="line-3247"></span>
-<span class="source-line-no">3248</span><span id="line-3248">  /**</span>
-<span class="source-line-no">3249</span><span id="line-3249">   * Set up correct timestamps in the KVs in Delete object.</span>
-<span class="source-line-no">3250</span><span id="line-3250">   * &lt;p/&gt;</span>
-<span class="source-line-no">3251</span><span id="line-3251">   * Caller should have the row and region locks.</span>
-<span class="source-line-no">3252</span><span id="line-3252">   */</span>
-<span class="source-line-no">3253</span><span id="line-3253">  private void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyMap,</span>
-<span class="source-line-no">3254</span><span id="line-3254">    byte[] byteNow) throws IOException {</span>
-<span class="source-line-no">3255</span><span id="line-3255">    for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; e : familyMap.entrySet()) {</span>
-<span class="source-line-no">3256</span><span id="line-3256"></span>
-<span class="source-line-no">3257</span><span id="line-3257">      byte[] family = e.getKey();</span>
-<span class="source-line-no">3258</span><span id="line-3258">      List&lt;ExtendedCell&gt; cells = e.getValue();</span>
-<span class="source-line-no">3259</span><span id="line-3259">      assert cells instanceof RandomAccess;</span>
-<span class="source-line-no">3260</span><span id="line-3260"></span>
-<span class="source-line-no">3261</span><span id="line-3261">      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
-<span class="source-line-no">3262</span><span id="line-3262">      int listSize = cells.size();</span>
-<span class="source-line-no">3263</span><span id="line-3263">      for (int i = 0; i &lt; listSize; i++) {</span>
-<span class="source-line-no">3264</span><span id="line-3264">        ExtendedCell cell = cells.get(i);</span>
-<span class="source-line-no">3265</span><span id="line-3265">        // Check if time is LATEST, change to time of most recent addition if so</span>
-<span class="source-line-no">3266</span><span id="line-3266">        // This is expensive.</span>
-<span class="source-line-no">3267</span><span id="line-3267">        if (</span>
-<span class="source-line-no">3268</span><span id="line-3268">          cell.getTimestamp() == HConstants.LATEST_TIMESTAMP &amp;&amp; PrivateCellUtil.isDeleteType(cell)</span>
-<span class="source-line-no">3269</span><span id="line-3269">        ) {</span>
-<span class="source-line-no">3270</span><span id="line-3270">          byte[] qual = CellUtil.cloneQualifier(cell);</span>
-<span class="source-line-no">3271</span><span id="line-3271"></span>
-<span class="source-line-no">3272</span><span id="line-3272">          Integer count = kvCount.get(qual);</span>
-<span class="source-line-no">3273</span><span id="line-3273">          if (count == null) {</span>
-<span class="source-line-no">3274</span><span id="line-3274">            kvCount.put(qual, 1);</span>
-<span class="source-line-no">3275</span><span id="line-3275">          } else {</span>
-<span class="source-line-no">3276</span><span id="line-3276">            kvCount.put(qual, count + 1);</span>
-<span class="source-line-no">3277</span><span id="line-3277">          }</span>
-<span class="source-line-no">3278</span><span id="line-3278">          count = kvCount.get(qual);</span>
-<span class="source-line-no">3279</span><span id="line-3279"></span>
-<span class="source-line-no">3280</span><span id="line-3280">          Get get = new Get(CellUtil.cloneRow(cell));</span>
-<span class="source-line-no">3281</span><span id="line-3281">          get.readVersions(count);</span>
-<span class="source-line-no">3282</span><span id="line-3282">          get.addColumn(family, qual);</span>
-<span class="source-line-no">3283</span><span id="line-3283">          if (coprocessorHost != null) {</span>
-<span class="source-line-no">3284</span><span id="line-3284">            if (</span>
-<span class="source-line-no">3285</span><span id="line-3285">              !coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell, byteNow, get)</span>
-<span class="source-line-no">3286</span><span id="line-3286">            ) {</span>
-<span class="source-line-no">3287</span><span id="line-3287">              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);</span>
-<span class="source-line-no">3288</span><span id="line-3288">            }</span>
-<span class="source-line-no">3289</span><span id="line-3289">          } else {</span>
-<span class="source-line-no">3290</span><span id="line-3290">            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);</span>
-<span class="source-line-no">3291</span><span id="line-3291">          }</span>
-<span class="source-line-no">3292</span><span id="line-3292">        } else {</span>
-<span class="source-line-no">3293</span><span id="line-3293">          PrivateCellUtil.updateLatestStamp(cell, byteNow);</span>
-<span class="source-line-no">3294</span><span id="line-3294">        }</span>
-<span class="source-line-no">3295</span><span id="line-3295">      }</span>
-<span class="source-line-no">3296</span><span id="line-3296">    }</span>
-<span class="source-line-no">3297</span><span id="line-3297">  }</span>
-<span class="source-line-no">3298</span><span id="line-3298"></span>
-<span class="source-line-no">3299</span><span id="line-3299">  private void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)</span>
-<span class="source-line-no">3300</span><span id="line-3300">    throws IOException {</span>
-<span class="source-line-no">3301</span><span id="line-3301">    try (RegionScanner scanner = getScanner(new Scan(get))) {</span>
-<span class="source-line-no">3302</span><span id="line-3302">      // NOTE: Please don't use HRegion.get() instead,</span>
-<span class="source-line-no">3303</span><span id="line-3303">      // because it will copy cells to heap. See HBASE-26036</span>
-<span class="source-line-no">3304</span><span id="line-3304">      List&lt;ExtendedCell&gt; result = new ArrayList&lt;&gt;();</span>
-<span class="source-line-no">3305</span><span id="line-3305">      scanner.next(result);</span>
-<span class="source-line-no">3306</span><span id="line-3306"></span>
-<span class="source-line-no">3307</span><span id="line-3307">      if (result.size() &lt; count) {</span>
-<span class="source-line-no">3308</span><span id="line-3308">        // Nothing to delete</span>
-<span class="source-line-no">3309</span><span id="line-3309">        PrivateCellUtil.updateLatestStamp(cell, byteNow);</span>
-<span class="source-line-no">3310</span><span id="line-3310">        return;</span>
-<span class="source-line-no">3311</span><span id="line-3311">      }</span>
-<span class="source-line-no">3312</span><span id="line-3312">      if (result.size() &gt; count) {</span>
-<span class="source-line-no">3313</span><span id="line-3313">        throw new RuntimeException("Unexpected size: " + result.size());</span>
-<span class="source-line-no">3314</span><span id="line-3314">      }</span>
-<span class="source-line-no">3315</span><span id="line-3315">      Cell getCell = result.get(count - 1);</span>
-<span class="source-line-no">3316</span><span id="line-3316">      PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());</span>
-<span class="source-line-no">3317</span><span id="line-3317">    }</span>
-<span class="source-line-no">3318</span><span id="line-3318">  }</span>
+<span class="source-line-no">3172</span><span id="line-3172">      throw dse;</span>
+<span class="source-line-no">3173</span><span id="line-3173">    }</span>
+<span class="source-line-no">3174</span><span id="line-3174"></span>
+<span class="source-line-no">3175</span><span id="line-3175">    // If we get to here, the HStores have been written.</span>
+<span class="source-line-no">3176</span><span id="line-3176">    if (wal != null) {</span>
+<span class="source-line-no">3177</span><span id="line-3177">      wal.completeCacheFlush(this.getRegionInfo().getEncodedNameAsBytes(), flushedSeqId);</span>
+<span class="source-line-no">3178</span><span id="line-3178">    }</span>
+<span class="source-line-no">3179</span><span id="line-3179"></span>
+<span class="source-line-no">3180</span><span id="line-3180">    // Record latest flush time</span>
+<span class="source-line-no">3181</span><span id="line-3181">    for (HStore store : storesToFlush) {</span>
+<span class="source-line-no">3182</span><span id="line-3182">      this.lastStoreFlushTimeMap.put(store, startTime);</span>
+<span class="source-line-no">3183</span><span id="line-3183">    }</span>
+<span class="source-line-no">3184</span><span id="line-3184"></span>
+<span class="source-line-no">3185</span><span id="line-3185">    this.maxFlushedSeqId = flushedSeqId;</span>
+<span class="source-line-no">3186</span><span id="line-3186">    this.lastFlushOpSeqId = flushOpSeqId;</span>
+<span class="source-line-no">3187</span><span id="line-3187"></span>
+<span class="source-line-no">3188</span><span id="line-3188">    // C. Finally notify anyone waiting on memstore to clear:</span>
+<span class="source-line-no">3189</span><span id="line-3189">    // e.g. checkResources().</span>
+<span class="source-line-no">3190</span><span id="line-3190">    synchronized (this) {</span>
+<span class="source-line-no">3191</span><span id="line-3191">      notifyAll(); // FindBugs NN_NAKED_NOTIFY</span>
+<span class="source-line-no">3192</span><span id="line-3192">    }</span>
+<span class="source-line-no">3193</span><span id="line-3193"></span>
+<span class="source-line-no">3194</span><span id="line-3194">    long time = EnvironmentEdgeManager.currentTime() - startTime;</span>
+<span class="source-line-no">3195</span><span id="line-3195">    MemStoreSize mss = prepareResult.totalFlushableSize.getMemStoreSize();</span>
+<span class="source-line-no">3196</span><span id="line-3196">    long memstoresize = this.memStoreSizing.getMemStoreSize().getDataSize();</span>
+<span class="source-line-no">3197</span><span id="line-3197">    String msg = "Finished flush of" + " dataSize ~" + StringUtils.byteDesc(mss.getDataSize()) + "/"</span>
+<span class="source-line-no">3198</span><span id="line-3198">      + mss.getDataSize() + ", heapSize ~" + StringUtils.byteDesc(mss.getHeapSize()) + "/"</span>
+<span class="source-line-no">3199</span><span id="line-3199">      + mss.getHeapSize() + ", currentSize=" + StringUtils.byteDesc(memstoresize) + "/"</span>
+<span class="source-line-no">3200</span><span id="line-3200">      + memstoresize + " for " + this.getRegionInfo().getEncodedName() + " in " + time</span>
+<span class="source-line-no">3201</span><span id="line-3201">      + "ms, sequenceid=" + flushOpSeqId + ", compaction requested=" + compactionRequested</span>
+<span class="source-line-no">3202</span><span id="line-3202">      + ((wal == null) ? "; wal=null" : "");</span>
+<span class="source-line-no">3203</span><span id="line-3203">    LOG.info(msg);</span>
+<span class="source-line-no">3204</span><span id="line-3204">    status.setStatus(msg);</span>
+<span class="source-line-no">3205</span><span id="line-3205"></span>
+<span class="source-line-no">3206</span><span id="line-3206">    if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {</span>
+<span class="source-line-no">3207</span><span id="line-3207">      rsServices.getMetrics().updateFlush(getTableDescriptor().getTableName().getNameAsString(),</span>
+<span class="source-line-no">3208</span><span id="line-3208">        time, mss.getDataSize(), flushedOutputFileSize);</span>
+<span class="source-line-no">3209</span><span id="line-3209">    }</span>
+<span class="source-line-no">3210</span><span id="line-3210"></span>
+<span class="source-line-no">3211</span><span id="line-3211">    return new FlushResultImpl(compactionRequested</span>
+<span class="source-line-no">3212</span><span id="line-3212">      ? FlushResult.Result.FLUSHED_COMPACTION_NEEDED</span>
+<span class="source-line-no">3213</span><span id="line-3213">      : FlushResult.Result.FLUSHED_NO_COMPACTION_NEEDED, flushOpSeqId);</span>
+<span class="source-line-no">3214</span><span id="line-3214">  }</span>
+<span class="source-line-no">3215</span><span id="line-3215"></span>
+<span class="source-line-no">3216</span><span id="line-3216">  /**</span>
+<span class="source-line-no">3217</span><span id="line-3217">   * Method to safely get the next sequence number.</span>
+<span class="source-line-no">3218</span><span id="line-3218">   * @return Next sequence number unassociated with any actual edit.</span>
+<span class="source-line-no">3219</span><span id="line-3219">   */</span>
+<span class="source-line-no">3220</span><span id="line-3220">  protected long getNextSequenceId(final WAL wal) throws IOException {</span>
+<span class="source-line-no">3221</span><span id="line-3221">    WriteEntry we = mvcc.begin();</span>
+<span class="source-line-no">3222</span><span id="line-3222">    mvcc.completeAndWait(we);</span>
+<span class="source-line-no">3223</span><span id="line-3223">    return we.getWriteNumber();</span>
+<span class="source-line-no">3224</span><span id="line-3224">  }</span>
+<span class="source-line-no">3225</span><span id="line-3225"></span>
+<span class="source-line-no">3226</span><span id="line-3226">  //////////////////////////////////////////////////////////////////////////////</span>
+<span class="source-line-no">3227</span><span id="line-3227">  // get() methods for client use.</span>
+<span class="source-line-no">3228</span><span id="line-3228">  //////////////////////////////////////////////////////////////////////////////</span>
+<span class="source-line-no">3229</span><span id="line-3229"></span>
+<span class="source-line-no">3230</span><span id="line-3230">  @Override</span>
+<span class="source-line-no">3231</span><span id="line-3231">  public RegionScannerImpl getScanner(Scan scan) throws IOException {</span>
+<span class="source-line-no">3232</span><span id="line-3232">    return getScanner(scan, null);</span>
+<span class="source-line-no">3233</span><span id="line-3233">  }</span>
+<span class="source-line-no">3234</span><span id="line-3234"></span>
+<span class="source-line-no">3235</span><span id="line-3235">  @Override</span>
+<span class="source-line-no">3236</span><span id="line-3236">  public RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners)</span>
+<span class="source-line-no">3237</span><span id="line-3237">    throws IOException {</span>
+<span class="source-line-no">3238</span><span id="line-3238">    return getScanner(scan, additionalScanners, HConstants.NO_NONCE, HConstants.NO_NONCE);</span>
+<span class="source-line-no">3239</span><span id="line-3239">  }</span>
+<span class="source-line-no">3240</span><span id="line-3240"></span>
+<span class="source-line-no">3241</span><span id="line-3241">  private RegionScannerImpl getScanner(Scan scan, List&lt;KeyValueScanner&gt; additionalScanners,</span>
+<span class="source-line-no">3242</span><span id="line-3242">    long nonceGroup, long nonce) throws IOException {</span>
+<span class="source-line-no">3243</span><span id="line-3243">    return TraceUtil.trace(() -&gt; {</span>
+<span class="source-line-no">3244</span><span id="line-3244">      startRegionOperation(Operation.SCAN);</span>
+<span class="source-line-no">3245</span><span id="line-3245">      try {</span>
+<span class="source-line-no">3246</span><span id="line-3246">        // Verify families are all valid</span>
+<span class="source-line-no">3247</span><span id="line-3247">        if (!scan.hasFamilies()) {</span>
+<span class="source-line-no">3248</span><span id="line-3248">          // Adding all families to scanner</span>
+<span class="source-line-no">3249</span><span id="line-3249">          for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {</span>
+<span class="source-line-no">3250</span><span id="line-3250">            scan.addFamily(family);</span>
+<span class="source-line-no">3251</span><span id="line-3251">          }</span>
+<span class="source-line-no">3252</span><span id="line-3252">        } else {</span>
+<span class="source-line-no">3253</span><span id="line-3253">          for (byte[] family : scan.getFamilyMap().keySet()) {</span>
+<span class="source-line-no">3254</span><span id="line-3254">            checkFamily(family);</span>
+<span class="source-line-no">3255</span><span id="line-3255">          }</span>
+<span class="source-line-no">3256</span><span id="line-3256">        }</span>
+<span class="source-line-no">3257</span><span id="line-3257">        return instantiateRegionScanner(scan, additionalScanners, nonceGroup, nonce);</span>
+<span class="source-line-no">3258</span><span id="line-3258">      } finally {</span>
+<span class="source-line-no">3259</span><span id="line-3259">        closeRegionOperation(Operation.SCAN);</span>
+<span class="source-line-no">3260</span><span id="line-3260">      }</span>
+<span class="source-line-no">3261</span><span id="line-3261">    }, () -&gt; createRegionSpan("Region.getScanner"));</span>
+<span class="source-line-no">3262</span><span id="line-3262">  }</span>
+<span class="source-line-no">3263</span><span id="line-3263"></span>
+<span class="source-line-no">3264</span><span id="line-3264">  protected RegionScannerImpl instantiateRegionScanner(Scan scan,</span>
+<span class="source-line-no">3265</span><span id="line-3265">    List&lt;KeyValueScanner&gt; additionalScanners, long nonceGroup, long nonce) throws IOException {</span>
+<span class="source-line-no">3266</span><span id="line-3266">    if (scan.isReversed()) {</span>
+<span class="source-line-no">3267</span><span id="line-3267">      if (scan.getFilter() != null) {</span>
+<span class="source-line-no">3268</span><span id="line-3268">        scan.getFilter().setReversed(true);</span>
+<span class="source-line-no">3269</span><span id="line-3269">      }</span>
+<span class="source-line-no">3270</span><span id="line-3270">      return new ReversedRegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);</span>
+<span class="source-line-no">3271</span><span id="line-3271">    }</span>
+<span class="source-line-no">3272</span><span id="line-3272">    return new RegionScannerImpl(scan, additionalScanners, this, nonceGroup, nonce);</span>
+<span class="source-line-no">3273</span><span id="line-3273">  }</span>
+<span class="source-line-no">3274</span><span id="line-3274"></span>
+<span class="source-line-no">3275</span><span id="line-3275">  /**</span>
+<span class="source-line-no">3276</span><span id="line-3276">   * Prepare a delete for a row mutation processor</span>
+<span class="source-line-no">3277</span><span id="line-3277">   * @param delete The passed delete is modified by this method. WARNING!</span>
+<span class="source-line-no">3278</span><span id="line-3278">   */</span>
+<span class="source-line-no">3279</span><span id="line-3279">  private void prepareDelete(Delete delete) throws IOException {</span>
+<span class="source-line-no">3280</span><span id="line-3280">    // Check to see if this is a deleteRow insert</span>
+<span class="source-line-no">3281</span><span id="line-3281">    if (delete.getFamilyCellMap().isEmpty()) {</span>
+<span class="source-line-no">3282</span><span id="line-3282">      for (byte[] family : this.htableDescriptor.getColumnFamilyNames()) {</span>
+<span class="source-line-no">3283</span><span id="line-3283">        // Don't eat the timestamp</span>
+<span class="source-line-no">3284</span><span id="line-3284">        delete.addFamily(family, delete.getTimestamp());</span>
+<span class="source-line-no">3285</span><span id="line-3285">      }</span>
+<span class="source-line-no">3286</span><span id="line-3286">    } else {</span>
+<span class="source-line-no">3287</span><span id="line-3287">      for (byte[] family : delete.getFamilyCellMap().keySet()) {</span>
+<span class="source-line-no">3288</span><span id="line-3288">        if (family == null) {</span>
+<span class="source-line-no">3289</span><span id="line-3289">          throw new NoSuchColumnFamilyException("Empty family is invalid");</span>
+<span class="source-line-no">3290</span><span id="line-3290">        }</span>
+<span class="source-line-no">3291</span><span id="line-3291">        checkFamily(family, delete.getDurability());</span>
+<span class="source-line-no">3292</span><span id="line-3292">      }</span>
+<span class="source-line-no">3293</span><span id="line-3293">    }</span>
+<span class="source-line-no">3294</span><span id="line-3294">  }</span>
+<span class="source-line-no">3295</span><span id="line-3295"></span>
+<span class="source-line-no">3296</span><span id="line-3296">  @Override</span>
+<span class="source-line-no">3297</span><span id="line-3297">  public void delete(Delete delete) throws IOException {</span>
+<span class="source-line-no">3298</span><span id="line-3298">    TraceUtil.trace(() -&gt; {</span>
+<span class="source-line-no">3299</span><span id="line-3299">      checkReadOnly();</span>
+<span class="source-line-no">3300</span><span id="line-3300">      checkResources();</span>
+<span class="source-line-no">3301</span><span id="line-3301">      startRegionOperation(Operation.DELETE);</span>
+<span class="source-line-no">3302</span><span id="line-3302">      try {</span>
+<span class="source-line-no">3303</span><span id="line-3303">        // All edits for the given row (across all column families) must happen atomically.</span>
+<span class="source-line-no">3304</span><span id="line-3304">        return mutate(delete);</span>
+<span class="source-line-no">3305</span><span id="line-3305">      } finally {</span>
+<span class="source-line-no">3306</span><span id="line-3306">        closeRegionOperation(Operation.DELETE);</span>
+<span class="source-line-no">3307</span><span id="line-3307">      }</span>
+<span class="source-line-no">3308</span><span id="line-3308">    }, () -&gt; createRegionSpan("Region.delete"));</span>
+<span class="source-line-no">3309</span><span id="line-3309">  }</span>
+<span class="source-line-no">3310</span><span id="line-3310"></span>
+<span class="source-line-no">3311</span><span id="line-3311">  /**</span>
+<span class="source-line-no">3312</span><span id="line-3312">   * Set up correct timestamps in the KVs in Delete object.</span>
+<span class="source-line-no">3313</span><span id="line-3313">   * &lt;p/&gt;</span>
+<span class="source-line-no">3314</span><span id="line-3314">   * Caller should have the row and region locks.</span>
+<span class="source-line-no">3315</span><span id="line-3315">   */</span>
+<span class="source-line-no">3316</span><span id="line-3316">  private void prepareDeleteTimestamps(Mutation mutation, Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyMap,</span>
+<span class="source-line-no">3317</span><span id="line-3317">    byte[] byteNow) throws IOException {</span>
+<span class="source-line-no">3318</span><span id="line-3318">    for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; e : familyMap.entrySet()) {</span>
 <span class="source-line-no">3319</span><span id="line-3319"></span>
-<span class="source-line-no">3320</span><span id="line-3320">  @Override</span>
-<span class="source-line-no">3321</span><span id="line-3321">  public void put(Put put) throws IOException {</span>
-<span class="source-line-no">3322</span><span id="line-3322">    TraceUtil.trace(() -&gt; {</span>
-<span class="source-line-no">3323</span><span id="line-3323">      checkReadOnly();</span>
-<span class="source-line-no">3324</span><span id="line-3324"></span>
-<span class="source-line-no">3325</span><span id="line-3325">      // Do a rough check that we have resources to accept a write. The check is</span>
-<span class="source-line-no">3326</span><span id="line-3326">      // 'rough' in that between the resource check and the call to obtain a</span>
-<span class="source-line-no">3327</span><span id="line-3327">      // read lock, resources may run out. For now, the thought is that this</span>
-<span class="source-line-no">3328</span><span id="line-3328">      // will be extremely rare; we'll deal with it when it happens.</span>
-<span class="source-line-no">3329</span><span id="line-3329">      checkResources();</span>
-<span class="source-line-no">3330</span><span id="line-3330">      startRegionOperation(Operation.PUT);</span>
-<span class="source-line-no">3331</span><span id="line-3331">      try {</span>
-<span class="source-line-no">3332</span><span id="line-3332">        // All edits for the given row (across all column families) must happen atomically.</span>
-<span class="source-line-no">3333</span><span id="line-3333">        return mutate(put);</span>
-<span class="source-line-no">3334</span><span id="line-3334">      } finally {</span>
-<span class="source-line-no">3335</span><span id="line-3335">        closeRegionOperation(Operation.PUT);</span>
-<span class="source-line-no">3336</span><span id="line-3336">      }</span>
-<span class="source-line-no">3337</span><span id="line-3337">    }, () -&gt; createRegionSpan("Region.put"));</span>
-<span class="source-line-no">3338</span><span id="line-3338">  }</span>
-<span class="source-line-no">3339</span><span id="line-3339"></span>
-<span class="source-line-no">3340</span><span id="line-3340">  /**</span>
-<span class="source-line-no">3341</span><span id="line-3341">   * Class that tracks the progress of a batch operations, accumulating status codes and tracking</span>
-<span class="source-line-no">3342</span><span id="line-3342">   * the index at which processing is proceeding. These batch operations may get split into</span>
-<span class="source-line-no">3343</span><span id="line-3343">   * mini-batches for processing.</span>
-<span class="source-line-no">3344</span><span id="line-3344">   */</span>
-<span class="source-line-no">3345</span><span id="line-3345">  private abstract static class BatchOperation&lt;T&gt; {</span>
-<span class="source-line-no">3346</span><span id="line-3346">    protected final T[] operations;</span>
-<span class="source-line-no">3347</span><span id="line-3347">    protected final OperationStatus[] retCodeDetails;</span>
-<span class="source-line-no">3348</span><span id="line-3348">    protected final WALEdit[] walEditsFromCoprocessors;</span>
-<span class="source-line-no">3349</span><span id="line-3349">    // reference family cell maps directly so coprocessors can mutate them if desired</span>
-<span class="source-line-no">3350</span><span id="line-3350">    protected final Map&lt;byte[], List&lt;ExtendedCell&gt;&gt;[] familyCellMaps;</span>
-<span class="source-line-no">3351</span><span id="line-3351">    // For Increment/Append operations</span>
-<span class="source-line-no">3352</span><span id="line-3352">    protected final Result[] results;</span>
-<span class="source-line-no">3353</span><span id="line-3353"></span>
-<span class="source-line-no">3354</span><span id="line-3354">    protected final HRegion region;</span>
-<span class="source-line-no">3355</span><span id="line-3355">    protected int nextIndexToProcess = 0;</span>
-<span class="source-line-no">3356</span><span id="line-3356">    protected final ObservedExceptionsInBatch observedExceptions;</span>
-<span class="source-line-no">3357</span><span id="line-3357">    // Durability of the batch (highest durability of all operations)</span>
-<span class="source-line-no">3358</span><span id="line-3358">    protected Durability durability;</span>
-<span class="source-line-no">3359</span><span id="line-3359">    protected boolean atomic = false;</span>
-<span class="source-line-no">3360</span><span id="line-3360"></span>
-<span class="source-line-no">3361</span><span id="line-3361">    public BatchOperation(final HRegion region, T[] operations) {</span>
-<span class="source-line-no">3362</span><span id="line-3362">      this.operations = operations;</span>
-<span class="source-line-no">3363</span><span id="line-3363">      this.retCodeDetails = new OperationStatus[operations.length];</span>
-<span class="source-line-no">3364</span><span id="line-3364">      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);</span>
-<span class="source-line-no">3365</span><span id="line-3365">      this.walEditsFromCoprocessors = new WALEdit[operations.length];</span>
-<span class="source-line-no">3366</span><span id="line-3366">      familyCellMaps = new Map[operations.length];</span>
-<span class="source-line-no">3367</span><span id="line-3367">      this.results = new Result[operations.length];</span>
-<span class="source-line-no">3368</span><span id="line-3368"></span>
-<span class="source-line-no">3369</span><span id="line-3369">      this.region = region;</span>
-<span class="source-line-no">3370</span><span id="line-3370">      observedExceptions = new ObservedExceptionsInBatch();</span>
-<span class="source-line-no">3371</span><span id="line-3371">      durability = Durability.USE_DEFAULT;</span>
-<span class="source-line-no">3372</span><span id="line-3372">    }</span>
-<span class="source-line-no">3373</span><span id="line-3373"></span>
-<span class="source-line-no">3374</span><span id="line-3374">    /**</span>
-<span class="source-line-no">3375</span><span id="line-3375">     * Visitor interface for batch operations</span>
-<span class="source-line-no">3376</span><span id="line-3376">     */</span>
-<span class="source-line-no">3377</span><span id="line-3377">    @FunctionalInterface</span>
-<span class="source-line-no">3378</span><span id="line-3378">    interface Visitor {</span>
-<span class="source-line-no">3379</span><span id="line-3379">      /**</span>
-<span class="source-line-no">3380</span><span id="line-3380">       * @param index operation index</span>
-<span class="source-line-no">3381</span><span id="line-3381">       * @return If true continue visiting remaining entries, break otherwise</span>
-<span class="source-line-no">3382</span><span id="line-3382">       */</span>
-<span class="source-line-no">3383</span><span id="line-3383">      boolean visit(int index) throws IOException;</span>
-<span class="source-line-no">3384</span><span id="line-3384">    }</span>
-<span class="source-line-no">3385</span><span id="line-3385"></span>
-<span class="source-line-no">3386</span><span id="line-3386">    /**</span>
-<span class="source-line-no">3387</span><span id="line-3387">     * Helper method for visiting pending/ all batch operations</span>
-<span class="source-line-no">3388</span><span id="line-3388">     */</span>
-<span class="source-line-no">3389</span><span id="line-3389">    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)</span>
-<span class="source-line-no">3390</span><span id="line-3390">      throws IOException {</span>
-<span class="source-line-no">3391</span><span id="line-3391">      assert lastIndexExclusive &lt;= this.size();</span>
-<span class="source-line-no">3392</span><span id="line-3392">      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {</span>
-<span class="source-line-no">3393</span><span id="line-3393">        if (!pendingOnly || isOperationPending(i)) {</span>
-<span class="source-line-no">3394</span><span id="line-3394">          if (!visitor.visit(i)) {</span>
-<span class="source-line-no">3395</span><span id="line-3395">            break;</span>
-<span class="source-line-no">3396</span><span id="line-3396">          }</span>
-<span class="source-line-no">3397</span><span id="line-3397">        }</span>
-<span class="source-line-no">3398</span><span id="line-3398">      }</span>
-<span class="source-line-no">3399</span><span id="line-3399">    }</span>
-<span class="source-line-no">3400</span><span id="line-3400"></span>
-<span class="source-line-no">3401</span><span id="line-3401">    public abstract Mutation getMutation(int index);</span>
+<span class="source-line-no">3320</span><span id="line-3320">      byte[] family = e.getKey();</span>
+<span class="source-line-no">3321</span><span id="line-3321">      List&lt;ExtendedCell&gt; cells = e.getValue();</span>
+<span class="source-line-no">3322</span><span id="line-3322">      assert cells instanceof RandomAccess;</span>
+<span class="source-line-no">3323</span><span id="line-3323"></span>
+<span class="source-line-no">3324</span><span id="line-3324">      Map&lt;byte[], Integer&gt; kvCount = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
+<span class="source-line-no">3325</span><span id="line-3325">      int listSize = cells.size();</span>
+<span class="source-line-no">3326</span><span id="line-3326">      for (int i = 0; i &lt; listSize; i++) {</span>
+<span class="source-line-no">3327</span><span id="line-3327">        ExtendedCell cell = cells.get(i);</span>
+<span class="source-line-no">3328</span><span id="line-3328">        // Check if time is LATEST, change to time of most recent addition if so</span>
+<span class="source-line-no">3329</span><span id="line-3329">        // This is expensive.</span>
+<span class="source-line-no">3330</span><span id="line-3330">        if (</span>
+<span class="source-line-no">3331</span><span id="line-3331">          cell.getTimestamp() == HConstants.LATEST_TIMESTAMP &amp;&amp; PrivateCellUtil.isDeleteType(cell)</span>
+<span class="source-line-no">3332</span><span id="line-3332">        ) {</span>
+<span class="source-line-no">3333</span><span id="line-3333">          byte[] qual = CellUtil.cloneQualifier(cell);</span>
+<span class="source-line-no">3334</span><span id="line-3334"></span>
+<span class="source-line-no">3335</span><span id="line-3335">          Integer count = kvCount.get(qual);</span>
+<span class="source-line-no">3336</span><span id="line-3336">          if (count == null) {</span>
+<span class="source-line-no">3337</span><span id="line-3337">            kvCount.put(qual, 1);</span>
+<span class="source-line-no">3338</span><span id="line-3338">          } else {</span>
+<span class="source-line-no">3339</span><span id="line-3339">            kvCount.put(qual, count + 1);</span>
+<span class="source-line-no">3340</span><span id="line-3340">          }</span>
+<span class="source-line-no">3341</span><span id="line-3341">          count = kvCount.get(qual);</span>
+<span class="source-line-no">3342</span><span id="line-3342"></span>
+<span class="source-line-no">3343</span><span id="line-3343">          Get get = new Get(CellUtil.cloneRow(cell));</span>
+<span class="source-line-no">3344</span><span id="line-3344">          get.readVersions(count);</span>
+<span class="source-line-no">3345</span><span id="line-3345">          get.addColumn(family, qual);</span>
+<span class="source-line-no">3346</span><span id="line-3346">          if (coprocessorHost != null) {</span>
+<span class="source-line-no">3347</span><span id="line-3347">            if (</span>
+<span class="source-line-no">3348</span><span id="line-3348">              !coprocessorHost.prePrepareTimeStampForDeleteVersion(mutation, cell, byteNow, get)</span>
+<span class="source-line-no">3349</span><span id="line-3349">            ) {</span>
+<span class="source-line-no">3350</span><span id="line-3350">              updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);</span>
+<span class="source-line-no">3351</span><span id="line-3351">            }</span>
+<span class="source-line-no">3352</span><span id="line-3352">          } else {</span>
+<span class="source-line-no">3353</span><span id="line-3353">            updateDeleteLatestVersionTimestamp(cell, get, count, byteNow);</span>
+<span class="source-line-no">3354</span><span id="line-3354">          }</span>
+<span class="source-line-no">3355</span><span id="line-3355">        } else {</span>
+<span class="source-line-no">3356</span><span id="line-3356">          PrivateCellUtil.updateLatestStamp(cell, byteNow);</span>
+<span class="source-line-no">3357</span><span id="line-3357">        }</span>
+<span class="source-line-no">3358</span><span id="line-3358">      }</span>
+<span class="source-line-no">3359</span><span id="line-3359">    }</span>
+<span class="source-line-no">3360</span><span id="line-3360">  }</span>
+<span class="source-line-no">3361</span><span id="line-3361"></span>
+<span class="source-line-no">3362</span><span id="line-3362">  private void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, byte[] byteNow)</span>
+<span class="source-line-no">3363</span><span id="line-3363">    throws IOException {</span>
+<span class="source-line-no">3364</span><span id="line-3364">    try (RegionScanner scanner = getScanner(new Scan(get))) {</span>
+<span class="source-line-no">3365</span><span id="line-3365">      // NOTE: Please don't use HRegion.get() instead,</span>
+<span class="source-line-no">3366</span><span id="line-3366">      // because it will copy cells to heap. See HBASE-26036</span>
+<span class="source-line-no">3367</span><span id="line-3367">      List&lt;ExtendedCell&gt; result = new ArrayList&lt;&gt;();</span>
+<span class="source-line-no">3368</span><span id="line-3368">      scanner.next(result);</span>
+<span class="source-line-no">3369</span><span id="line-3369"></span>
+<span class="source-line-no">3370</span><span id="line-3370">      if (result.size() &lt; count) {</span>
+<span class="source-line-no">3371</span><span id="line-3371">        // Nothing to delete</span>
+<span class="source-line-no">3372</span><span id="line-3372">        PrivateCellUtil.updateLatestStamp(cell, byteNow);</span>
+<span class="source-line-no">3373</span><span id="line-3373">        return;</span>
+<span class="source-line-no">3374</span><span id="line-3374">      }</span>
+<span class="source-line-no">3375</span><span id="line-3375">      if (result.size() &gt; count) {</span>
+<span class="source-line-no">3376</span><span id="line-3376">        throw new RuntimeException("Unexpected size: " + result.size());</span>
+<span class="source-line-no">3377</span><span id="line-3377">      }</span>
+<span class="source-line-no">3378</span><span id="line-3378">      Cell getCell = result.get(count - 1);</span>
+<span class="source-line-no">3379</span><span id="line-3379">      PrivateCellUtil.setTimestamp(cell, getCell.getTimestamp());</span>
+<span class="source-line-no">3380</span><span id="line-3380">    }</span>
+<span class="source-line-no">3381</span><span id="line-3381">  }</span>
+<span class="source-line-no">3382</span><span id="line-3382"></span>
+<span class="source-line-no">3383</span><span id="line-3383">  @Override</span>
+<span class="source-line-no">3384</span><span id="line-3384">  public void put(Put put) throws IOException {</span>
+<span class="source-line-no">3385</span><span id="line-3385">    TraceUtil.trace(() -&gt; {</span>
+<span class="source-line-no">3386</span><span id="line-3386">      checkReadOnly();</span>
+<span class="source-line-no">3387</span><span id="line-3387"></span>
+<span class="source-line-no">3388</span><span id="line-3388">      // Do a rough check that we have resources to accept a write. The check is</span>
+<span class="source-line-no">3389</span><span id="line-3389">      // 'rough' in that between the resource check and the call to obtain a</span>
+<span class="source-line-no">3390</span><span id="line-3390">      // read lock, resources may run out. For now, the thought is that this</span>
+<span class="source-line-no">3391</span><span id="line-3391">      // will be extremely rare; we'll deal with it when it happens.</span>
+<span class="source-line-no">3392</span><span id="line-3392">      checkResources();</span>
+<span class="source-line-no">3393</span><span id="line-3393">      startRegionOperation(Operation.PUT);</span>
+<span class="source-line-no">3394</span><span id="line-3394">      try {</span>
+<span class="source-line-no">3395</span><span id="line-3395">        // All edits for the given row (across all column families) must happen atomically.</span>
+<span class="source-line-no">3396</span><span id="line-3396">        return mutate(put);</span>
+<span class="source-line-no">3397</span><span id="line-3397">      } finally {</span>
+<span class="source-line-no">3398</span><span id="line-3398">        closeRegionOperation(Operation.PUT);</span>
+<span class="source-line-no">3399</span><span id="line-3399">      }</span>
+<span class="source-line-no">3400</span><span id="line-3400">    }, () -&gt; createRegionSpan("Region.put"));</span>
+<span class="source-line-no">3401</span><span id="line-3401">  }</span>
 <span class="source-line-no">3402</span><span id="line-3402"></span>
-<span class="source-line-no">3403</span><span id="line-3403">    public abstract long getNonceGroup(int index);</span>
-<span class="source-line-no">3404</span><span id="line-3404"></span>
-<span class="source-line-no">3405</span><span id="line-3405">    public abstract long getNonce(int index);</span>
-<span class="source-line-no">3406</span><span id="line-3406"></span>
-<span class="source-line-no">3407</span><span id="line-3407">    /**</span>
-<span class="source-line-no">3408</span><span id="line-3408">     * This method is potentially expensive and useful mostly for non-replay CP path.</span>
-<span class="source-line-no">3409</span><span id="line-3409">     */</span>
-<span class="source-line-no">3410</span><span id="line-3410">    public abstract Mutation[] getMutationsForCoprocs();</span>
-<span class="source-line-no">3411</span><span id="line-3411"></span>
-<span class="source-line-no">3412</span><span id="line-3412">    public abstract boolean isInReplay();</span>
-<span class="source-line-no">3413</span><span id="line-3413"></span>
-<span class="source-line-no">3414</span><span id="line-3414">    public abstract long getOrigLogSeqNum();</span>
-<span class="source-line-no">3415</span><span id="line-3415"></span>
-<span class="source-line-no">3416</span><span id="line-3416">    public abstract void startRegionOperation() throws IOException;</span>
-<span class="source-line-no">3417</span><span id="line-3417"></span>
-<span class="source-line-no">3418</span><span id="line-3418">    public abstract void closeRegionOperation() throws IOException;</span>
-<span class="source-line-no">3419</span><span id="line-3419"></span>
-<span class="source-line-no">3420</span><span id="line-3420">    /**</span>
-<span class="source-line-no">3421</span><span id="line-3421">     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs</span>
-<span class="source-line-no">3422</span><span id="line-3422">     * CP prePut()/preDelete()/preIncrement()/preAppend() hooks for all mutations in a batch. This</span>
-<span class="source-line-no">3423</span><span id="line-3423">     * is intended to operate on entire batch and will be called from outside of class to check and</span>
-<span class="source-line-no">3424</span><span id="line-3424">     * prepare batch. This can be implemented by calling helper method</span>
-<span class="source-line-no">3425</span><span id="line-3425">     * {@link #checkAndPrepareMutation(int, long)} in a 'for' loop over mutations.</span>
-<span class="source-line-no">3426</span><span id="line-3426">     */</span>
-<span class="source-line-no">3427</span><span id="line-3427">    public abstract void checkAndPrepare() throws IOException;</span>
-<span class="source-line-no">3428</span><span id="line-3428"></span>
-<span class="source-line-no">3429</span><span id="line-3429">    /**</span>
-<span class="source-line-no">3430</span><span id="line-3430">     * Implement any Put request specific check and prepare logic here. Please refer to</span>
-<span class="source-line-no">3431</span><span id="line-3431">     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.</span>
-<span class="source-line-no">3432</span><span id="line-3432">     */</span>
-<span class="source-line-no">3433</span><span id="line-3433">    protected abstract void checkAndPreparePut(final Put p) throws IOException;</span>
-<span class="source-line-no">3434</span><span id="line-3434"></span>
-<span class="source-line-no">3435</span><span id="line-3435">    /**</span>
-<span class="source-line-no">3436</span><span id="line-3436">     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell</span>
-<span class="source-line-no">3437</span><span id="line-3437">     * count, tags and timestamp for all cells of all operations in a mini-batch.</span>
-<span class="source-line-no">3438</span><span id="line-3438">     */</span>
-<span class="source-line-no">3439</span><span id="line-3439">    public abstract void prepareMiniBatchOperations(</span>
-<span class="source-line-no">3440</span><span id="line-3440">      MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, long timestamp,</span>
-<span class="source-line-no">3441</span><span id="line-3441">      final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;</span>
-<span class="source-line-no">3442</span><span id="line-3442"></span>
-<span class="source-line-no">3443</span><span id="line-3443">    /**</span>
-<span class="source-line-no">3444</span><span id="line-3444">     * Write mini-batch operations to MemStore</span>
-<span class="source-line-no">3445</span><span id="line-3445">     */</span>
-<span class="source-line-no">3446</span><span id="line-3446">    public abstract WriteEntry writeMiniBatchOperationsToMemStore(</span>
-<span class="source-line-no">3447</span><span id="line-3447">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry,</span>
-<span class="source-line-no">3448</span><span id="line-3448">      long now) throws IOException;</span>
-<span class="source-line-no">3449</span><span id="line-3449"></span>
-<span class="source-line-no">3450</span><span id="line-3450">    protected void writeMiniBatchOperationsToMemStore(</span>
-<span class="source-line-no">3451</span><span id="line-3451">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)</span>
-<span class="source-line-no">3452</span><span id="line-3452">      throws IOException {</span>
-<span class="source-line-no">3453</span><span id="line-3453">      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();</span>
-<span class="source-line-no">3454</span><span id="line-3454">      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {</span>
-<span class="source-line-no">3455</span><span id="line-3455">        // We need to update the sequence id for following reasons.</span>
-<span class="source-line-no">3456</span><span id="line-3456">        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.</span>
-<span class="source-line-no">3457</span><span id="line-3457">        // 2) If no WAL, FSWALEntry won't be used</span>
-<span class="source-line-no">3458</span><span id="line-3458">        // we use durability of the original mutation for the mutation passed by CP.</span>
-<span class="source-line-no">3459</span><span id="line-3459">        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {</span>
-<span class="source-line-no">3460</span><span id="line-3460">          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);</span>
-<span class="source-line-no">3461</span><span id="line-3461">        }</span>
-<span class="source-line-no">3462</span><span id="line-3462">        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);</span>
-<span class="source-line-no">3463</span><span id="line-3463">        return true;</span>
-<span class="source-line-no">3464</span><span id="line-3464">      });</span>
-<span class="source-line-no">3465</span><span id="line-3465">      // update memStore size</span>
-<span class="source-line-no">3466</span><span id="line-3466">      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),</span>
-<span class="source-line-no">3467</span><span id="line-3467">        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());</span>
-<span class="source-line-no">3468</span><span id="line-3468">    }</span>
+<span class="source-line-no">3403</span><span id="line-3403">  /**</span>
+<span class="source-line-no">3404</span><span id="line-3404">   * Class that tracks the progress of a batch operations, accumulating status codes and tracking</span>
+<span class="source-line-no">3405</span><span id="line-3405">   * the index at which processing is proceeding. These batch operations may get split into</span>
+<span class="source-line-no">3406</span><span id="line-3406">   * mini-batches for processing.</span>
+<span class="source-line-no">3407</span><span id="line-3407">   */</span>
+<span class="source-line-no">3408</span><span id="line-3408">  private abstract static class BatchOperation&lt;T&gt; {</span>
+<span class="source-line-no">3409</span><span id="line-3409">    protected final T[] operations;</span>
+<span class="source-line-no">3410</span><span id="line-3410">    protected final OperationStatus[] retCodeDetails;</span>
+<span class="source-line-no">3411</span><span id="line-3411">    protected final WALEdit[] walEditsFromCoprocessors;</span>
+<span class="source-line-no">3412</span><span id="line-3412">    // reference family cell maps directly so coprocessors can mutate them if desired</span>
+<span class="source-line-no">3413</span><span id="line-3413">    protected final Map&lt;byte[], List&lt;ExtendedCell&gt;&gt;[] familyCellMaps;</span>
+<span class="source-line-no">3414</span><span id="line-3414">    // For Increment/Append operations</span>
+<span class="source-line-no">3415</span><span id="line-3415">    protected final Result[] results;</span>
+<span class="source-line-no">3416</span><span id="line-3416"></span>
+<span class="source-line-no">3417</span><span id="line-3417">    protected final HRegion region;</span>
+<span class="source-line-no">3418</span><span id="line-3418">    protected int nextIndexToProcess = 0;</span>
+<span class="source-line-no">3419</span><span id="line-3419">    protected final ObservedExceptionsInBatch observedExceptions;</span>
+<span class="source-line-no">3420</span><span id="line-3420">    // Durability of the batch (highest durability of all operations)</span>
+<span class="source-line-no">3421</span><span id="line-3421">    protected Durability durability;</span>
+<span class="source-line-no">3422</span><span id="line-3422">    protected boolean atomic = false;</span>
+<span class="source-line-no">3423</span><span id="line-3423"></span>
+<span class="source-line-no">3424</span><span id="line-3424">    public BatchOperation(final HRegion region, T[] operations) {</span>
+<span class="source-line-no">3425</span><span id="line-3425">      this.operations = operations;</span>
+<span class="source-line-no">3426</span><span id="line-3426">      this.retCodeDetails = new OperationStatus[operations.length];</span>
+<span class="source-line-no">3427</span><span id="line-3427">      Arrays.fill(this.retCodeDetails, OperationStatus.NOT_RUN);</span>
+<span class="source-line-no">3428</span><span id="line-3428">      this.walEditsFromCoprocessors = new WALEdit[operations.length];</span>
+<span class="source-line-no">3429</span><span id="line-3429">      familyCellMaps = new Map[operations.length];</span>
+<span class="source-line-no">3430</span><span id="line-3430">      this.results = new Result[operations.length];</span>
+<span class="source-line-no">3431</span><span id="line-3431"></span>
+<span class="source-line-no">3432</span><span id="line-3432">      this.region = region;</span>
+<span class="source-line-no">3433</span><span id="line-3433">      observedExceptions = new ObservedExceptionsInBatch();</span>
+<span class="source-line-no">3434</span><span id="line-3434">      durability = Durability.USE_DEFAULT;</span>
+<span class="source-line-no">3435</span><span id="line-3435">    }</span>
+<span class="source-line-no">3436</span><span id="line-3436"></span>
+<span class="source-line-no">3437</span><span id="line-3437">    /**</span>
+<span class="source-line-no">3438</span><span id="line-3438">     * Visitor interface for batch operations</span>
+<span class="source-line-no">3439</span><span id="line-3439">     */</span>
+<span class="source-line-no">3440</span><span id="line-3440">    @FunctionalInterface</span>
+<span class="source-line-no">3441</span><span id="line-3441">    interface Visitor {</span>
+<span class="source-line-no">3442</span><span id="line-3442">      /**</span>
+<span class="source-line-no">3443</span><span id="line-3443">       * @param index operation index</span>
+<span class="source-line-no">3444</span><span id="line-3444">       * @return If true continue visiting remaining entries, break otherwise</span>
+<span class="source-line-no">3445</span><span id="line-3445">       */</span>
+<span class="source-line-no">3446</span><span id="line-3446">      boolean visit(int index) throws IOException;</span>
+<span class="source-line-no">3447</span><span id="line-3447">    }</span>
+<span class="source-line-no">3448</span><span id="line-3448"></span>
+<span class="source-line-no">3449</span><span id="line-3449">    /**</span>
+<span class="source-line-no">3450</span><span id="line-3450">     * Helper method for visiting pending/ all batch operations</span>
+<span class="source-line-no">3451</span><span id="line-3451">     */</span>
+<span class="source-line-no">3452</span><span id="line-3452">    public void visitBatchOperations(boolean pendingOnly, int lastIndexExclusive, Visitor visitor)</span>
+<span class="source-line-no">3453</span><span id="line-3453">      throws IOException {</span>
+<span class="source-line-no">3454</span><span id="line-3454">      assert lastIndexExclusive &lt;= this.size();</span>
+<span class="source-line-no">3455</span><span id="line-3455">      for (int i = nextIndexToProcess; i &lt; lastIndexExclusive; i++) {</span>
+<span class="source-line-no">3456</span><span id="line-3456">        if (!pendingOnly || isOperationPending(i)) {</span>
+<span class="source-line-no">3457</span><span id="line-3457">          if (!visitor.visit(i)) {</span>
+<span class="source-line-no">3458</span><span id="line-3458">            break;</span>
+<span class="source-line-no">3459</span><span id="line-3459">          }</span>
+<span class="source-line-no">3460</span><span id="line-3460">        }</span>
+<span class="source-line-no">3461</span><span id="line-3461">      }</span>
+<span class="source-line-no">3462</span><span id="line-3462">    }</span>
+<span class="source-line-no">3463</span><span id="line-3463"></span>
+<span class="source-line-no">3464</span><span id="line-3464">    public abstract Mutation getMutation(int index);</span>
+<span class="source-line-no">3465</span><span id="line-3465"></span>
+<span class="source-line-no">3466</span><span id="line-3466">    public abstract long getNonceGroup(int index);</span>
+<span class="source-line-no">3467</span><span id="line-3467"></span>
+<span class="source-line-no">3468</span><span id="line-3468">    public abstract long getNonce(int index);</span>
 <span class="source-line-no">3469</span><span id="line-3469"></span>
-<span class="source-line-no">3470</span><span id="line-3470">    public boolean isDone() {</span>
-<span class="source-line-no">3471</span><span id="line-3471">      return nextIndexToProcess == operations.length;</span>
-<span class="source-line-no">3472</span><span id="line-3472">    }</span>
-<span class="source-line-no">3473</span><span id="line-3473"></span>
-<span class="source-line-no">3474</span><span id="line-3474">    public int size() {</span>
-<span class="source-line-no">3475</span><span id="line-3475">      return operations.length;</span>
-<span class="source-line-no">3476</span><span id="line-3476">    }</span>
-<span class="source-line-no">3477</span><span id="line-3477"></span>
-<span class="source-line-no">3478</span><span id="line-3478">    public boolean isOperationPending(int index) {</span>
-<span class="source-line-no">3479</span><span id="line-3479">      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;</span>
-<span class="source-line-no">3480</span><span id="line-3480">    }</span>
-<span class="source-line-no">3481</span><span id="line-3481"></span>
-<span class="source-line-no">3482</span><span id="line-3482">    public List&lt;UUID&gt; getClusterIds() {</span>
-<span class="source-line-no">3483</span><span id="line-3483">      assert size() != 0;</span>
-<span class="source-line-no">3484</span><span id="line-3484">      return getMutation(0).getClusterIds();</span>
-<span class="source-line-no">3485</span><span id="line-3485">    }</span>
-<span class="source-line-no">3486</span><span id="line-3486"></span>
-<span class="source-line-no">3487</span><span id="line-3487">    boolean isAtomic() {</span>
-<span class="source-line-no">3488</span><span id="line-3488">      return atomic;</span>
-<span class="source-line-no">3489</span><span id="line-3489">    }</span>
-<span class="source-line-no">3490</span><span id="line-3490"></span>
-<span class="source-line-no">3491</span><span id="line-3491">    /**</span>
-<span class="source-line-no">3492</span><span id="line-3492">     * Helper method that checks and prepares only one mutation. This can be used to implement</span>
-<span class="source-line-no">3493</span><span id="line-3493">     * {@link #checkAndPrepare()} for entire Batch. NOTE: As CP</span>
-<span class="source-line-no">3494</span><span id="line-3494">     * prePut()/preDelete()/preIncrement()/preAppend() hooks may modify mutations, this method</span>
-<span class="source-line-no">3495</span><span id="line-3495">     * should be called after prePut()/preDelete()/preIncrement()/preAppend() CP hooks are run for</span>
-<span class="source-line-no">3496</span><span id="line-3496">     * the mutation</span>
-<span class="source-line-no">3497</span><span id="line-3497">     */</span>
-<span class="source-line-no">3498</span><span id="line-3498">    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)</span>
-<span class="source-line-no">3499</span><span id="line-3499">      throws IOException {</span>
-<span class="source-line-no">3500</span><span id="line-3500">      region.checkRow(mutation.getRow(), "batchMutate");</span>
-<span class="source-line-no">3501</span><span id="line-3501">      if (mutation instanceof Put) {</span>
-<span class="source-line-no">3502</span><span id="line-3502">        // Check the families in the put. If bad, skip this one.</span>
-<span class="source-line-no">3503</span><span id="line-3503">        checkAndPreparePut((Put) mutation);</span>
-<span class="source-line-no">3504</span><span id="line-3504">        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);</span>
-<span class="source-line-no">3505</span><span id="line-3505">      } else if (mutation instanceof Delete) {</span>
-<span class="source-line-no">3506</span><span id="line-3506">        region.prepareDelete((Delete) mutation);</span>
-<span class="source-line-no">3507</span><span id="line-3507">      } else if (mutation instanceof Increment || mutation instanceof Append) {</span>
-<span class="source-line-no">3508</span><span id="line-3508">        region.checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());</span>
-<span class="source-line-no">3509</span><span id="line-3509">      }</span>
-<span class="source-line-no">3510</span><span id="line-3510">    }</span>
-<span class="source-line-no">3511</span><span id="line-3511"></span>
-<span class="source-line-no">3512</span><span id="line-3512">    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {</span>
-<span class="source-line-no">3513</span><span id="line-3513">      Mutation mutation = getMutation(index);</span>
-<span class="source-line-no">3514</span><span id="line-3514">      try {</span>
-<span class="source-line-no">3515</span><span id="line-3515">        this.checkAndPrepareMutation(mutation, timestamp);</span>
-<span class="source-line-no">3516</span><span id="line-3516"></span>
-<span class="source-line-no">3517</span><span id="line-3517">        if (mutation instanceof Put || mutation instanceof Delete) {</span>
-<span class="source-line-no">3518</span><span id="line-3518">          // store the family map reference to allow for mutations</span>
-<span class="source-line-no">3519</span><span id="line-3519">          // we know that in mutation, only ExtendedCells are allow so here we do a fake cast, to</span>
-<span class="source-line-no">3520</span><span id="line-3520">          // simplify later logic</span>
-<span class="source-line-no">3521</span><span id="line-3521">          familyCellMaps[index] = ClientInternalHelper.getExtendedFamilyCellMap(mutation);</span>
-<span class="source-line-no">3522</span><span id="line-3522">        }</span>
-<span class="source-line-no">3523</span><span id="line-3523"></span>
-<span class="source-line-no">3524</span><span id="line-3524">        // store durability for the batch (highest durability of all operations in the batch)</span>
-<span class="source-line-no">3525</span><span id="line-3525">        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());</span>
-<span class="source-line-no">3526</span><span id="line-3526">        if (tmpDur.ordinal() &gt; durability.ordinal()) {</span>
-<span class="source-line-no">3527</span><span id="line-3527">          durability = tmpDur;</span>
-<span class="source-line-no">3528</span><span id="line-3528">        }</span>
-<span class="source-line-no">3529</span><span id="line-3529">      } catch (NoSuchColumnFamilyException nscfe) {</span>
-<span class="source-line-no">3530</span><span id="line-3530">        final String msg = "No such column family in batch mutation in region " + this;</span>
-<span class="source-line-no">3531</span><span id="line-3531">        if (observedExceptions.hasSeenNoSuchFamily()) {</span>
-<span class="source-line-no">3532</span><span id="line-3532">          LOG.warn(msg + nscfe.getMessage());</span>
-<span class="source-line-no">3533</span><span id="line-3533">        } else {</span>
-<span class="source-line-no">3534</span><span id="line-3534">          LOG.warn(msg, nscfe);</span>
-<span class="source-line-no">3535</span><span id="line-3535">          observedExceptions.sawNoSuchFamily();</span>
-<span class="source-line-no">3536</span><span id="line-3536">        }</span>
-<span class="source-line-no">3537</span><span id="line-3537">        retCodeDetails[index] =</span>
-<span class="source-line-no">3538</span><span id="line-3538">          new OperationStatus(OperationStatusCode.BAD_FAMILY, nscfe.getMessage());</span>
-<span class="source-line-no">3539</span><span id="line-3539">        if (isAtomic()) { // fail, atomic means all or none</span>
-<span class="source-line-no">3540</span><span id="line-3540">          throw nscfe;</span>
-<span class="source-line-no">3541</span><span id="line-3541">        }</span>
-<span class="source-line-no">3542</span><span id="line-3542">      } catch (FailedSanityCheckException fsce) {</span>
-<span class="source-line-no">3543</span><span id="line-3543">        final String msg = "Batch Mutation did not pass sanity check in region " + this;</span>
-<span class="source-line-no">3544</span><span id="line-3544">        if (observedExceptions.hasSeenFailedSanityCheck()) {</span>
-<span class="source-line-no">3545</span><span id="line-3545">          LOG.warn(msg + fsce.getMessage());</span>
-<span class="source-line-no">3546</span><span id="line-3546">        } else {</span>
-<span class="source-line-no">3547</span><span id="line-3547">          LOG.warn(msg, fsce);</span>
-<span class="source-line-no">3548</span><span id="line-3548">          observedExceptions.sawFailedSanityCheck();</span>
-<span class="source-line-no">3549</span><span id="line-3549">        }</span>
-<span class="source-line-no">3550</span><span id="line-3550">        retCodeDetails[index] =</span>
-<span class="source-line-no">3551</span><span id="line-3551">          new OperationStatus(OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());</span>
-<span class="source-line-no">3552</span><span id="line-3552">        if (isAtomic()) {</span>
-<span class="source-line-no">3553</span><span id="line-3553">          throw fsce;</span>
-<span class="source-line-no">3554</span><span id="line-3554">        }</span>
-<span class="source-line-no">3555</span><span id="line-3555">      } catch (WrongRegionException we) {</span>
-<span class="source-line-no">3556</span><span id="line-3556">        final String msg = "Batch mutation had a row that does not belong to this region " + this;</span>
-<span class="source-line-no">3557</span><span id="line-3557">        if (observedExceptions.hasSeenWrongRegion()) {</span>
-<span class="source-line-no">3558</span><span id="line-3558">          LOG.warn(msg + we.getMessage());</span>
-<span class="source-line-no">3559</span><span id="line-3559">        } else {</span>
-<span class="source-line-no">3560</span><span id="line-3560">          LOG.warn(msg, we);</span>
-<span class="source-line-no">3561</span><span id="line-3561">          observedExceptions.sawWrongRegion();</span>
-<span class="source-line-no">3562</span><span id="line-3562">        }</span>
-<span class="source-line-no">3563</span><span id="line-3563">        retCodeDetails[index] =</span>
-<span class="source-line-no">3564</span><span id="line-3564">          new OperationStatus(OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());</span>
-<span class="source-line-no">3565</span><span id="line-3565">        if (isAtomic()) {</span>
-<span class="source-line-no">3566</span><span id="line-3566">          throw we;</span>
-<span class="source-line-no">3567</span><span id="line-3567">        }</span>
-<span class="source-line-no">3568</span><span id="line-3568">      }</span>
-<span class="source-line-no">3569</span><span id="line-3569">    }</span>
-<span class="source-line-no">3570</span><span id="line-3570"></span>
-<span class="source-line-no">3571</span><span id="line-3571">    /**</span>
-<span class="source-line-no">3572</span><span id="line-3572">     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which a row</span>
-<span class="source-line-no">3573</span><span id="line-3573">     * lock can be acquired. All mutations with locked rows are considered to be In-progress</span>
-<span class="source-line-no">3574</span><span id="line-3574">     * operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch is window over</span>
-<span class="source-line-no">3575</span><span id="line-3575">     * {@link BatchOperation} and contains contiguous pending operations.</span>
-<span class="source-line-no">3576</span><span id="line-3576">     * @param acquiredRowLocks keeps track of rowLocks acquired.</span>
-<span class="source-line-no">3577</span><span id="line-3577">     */</span>
-<span class="source-line-no">3578</span><span id="line-3578">    public MiniBatchOperationInProgress&lt;Mutation&gt;</span>
-<span class="source-line-no">3579</span><span id="line-3579">      lockRowsAndBuildMiniBatch(List&lt;RowLock&gt; acquiredRowLocks) throws IOException {</span>
-<span class="source-line-no">3580</span><span id="line-3580">      int readyToWriteCount = 0;</span>
-<span class="source-line-no">3581</span><span id="line-3581">      int lastIndexExclusive = 0;</span>
-<span class="source-line-no">3582</span><span id="line-3582">      RowLock prevRowLock = null;</span>
-<span class="source-line-no">3583</span><span id="line-3583">      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {</span>
-<span class="source-line-no">3584</span><span id="line-3584">        // It reaches the miniBatchSize, stop here and process the miniBatch</span>
-<span class="source-line-no">3585</span><span id="line-3585">        // This only applies to non-atomic batch operations.</span>
-<span class="source-line-no">3586</span><span id="line-3586">        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {</span>
-<span class="source-line-no">3587</span><span id="line-3587">          break;</span>
-<span class="source-line-no">3588</span><span id="line-3588">        }</span>
-<span class="source-line-no">3589</span><span id="line-3589"></span>
-<span class="source-line-no">3590</span><span id="line-3590">        if (!isOperationPending(lastIndexExclusive)) {</span>
-<span class="source-line-no">3591</span><span id="line-3591">          continue;</span>
-<span class="source-line-no">3592</span><span id="line-3592">        }</span>
-<span class="source-line-no">3593</span><span id="line-3593"></span>
-<span class="source-line-no">3594</span><span id="line-3594">        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting</span>
-<span class="source-line-no">3595</span><span id="line-3595">        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation</span>
-<span class="source-line-no">3596</span><span id="line-3596">        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't</span>
-<span class="source-line-no">3597</span><span id="line-3597">        // pass the isOperationPending check</span>
-<span class="source-line-no">3598</span><span id="line-3598">        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =</span>
-<span class="source-line-no">3599</span><span id="line-3599">          getMutation(lastIndexExclusive).getFamilyCellMap();</span>
-<span class="source-line-no">3600</span><span id="line-3600">        try {</span>
-<span class="source-line-no">3601</span><span id="line-3601">          // start the protector before acquiring row lock considering performance, and will finish</span>
-<span class="source-line-no">3602</span><span id="line-3602">          // it when encountering exception</span>
-<span class="source-line-no">3603</span><span id="line-3603">          region.storeHotnessProtector.start(curFamilyCellMap);</span>
-<span class="source-line-no">3604</span><span id="line-3604">        } catch (RegionTooBusyException rtbe) {</span>
-<span class="source-line-no">3605</span><span id="line-3605">          region.storeHotnessProtector.finish(curFamilyCellMap);</span>
-<span class="source-line-no">3606</span><span id="line-3606">          if (isAtomic()) {</span>
-<span class="source-line-no">3607</span><span id="line-3607">            throw rtbe;</span>
-<span class="source-line-no">3608</span><span id="line-3608">          }</span>
-<span class="source-line-no">3609</span><span id="line-3609">          retCodeDetails[lastIndexExclusive] =</span>
-<span class="source-line-no">3610</span><span id="line-3610">            new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());</span>
-<span class="source-line-no">3611</span><span id="line-3611">          continue;</span>
+<span class="source-line-no">3470</span><span id="line-3470">    /**</span>
+<span class="source-line-no">3471</span><span id="line-3471">     * This method is potentially expensive and useful mostly for non-replay CP path.</span>
+<span class="source-line-no">3472</span><span id="line-3472">     */</span>
+<span class="source-line-no">3473</span><span id="line-3473">    public abstract Mutation[] getMutationsForCoprocs();</span>
+<span class="source-line-no">3474</span><span id="line-3474"></span>
+<span class="source-line-no">3475</span><span id="line-3475">    public abstract boolean isInReplay();</span>
+<span class="source-line-no">3476</span><span id="line-3476"></span>
+<span class="source-line-no">3477</span><span id="line-3477">    public abstract long getOrigLogSeqNum();</span>
+<span class="source-line-no">3478</span><span id="line-3478"></span>
+<span class="source-line-no">3479</span><span id="line-3479">    public abstract void startRegionOperation() throws IOException;</span>
+<span class="source-line-no">3480</span><span id="line-3480"></span>
+<span class="source-line-no">3481</span><span id="line-3481">    public abstract void closeRegionOperation() throws IOException;</span>
+<span class="source-line-no">3482</span><span id="line-3482"></span>
+<span class="source-line-no">3483</span><span id="line-3483">    /**</span>
+<span class="source-line-no">3484</span><span id="line-3484">     * Validates each mutation and prepares a batch for write. If necessary (non-replay case), runs</span>
+<span class="source-line-no">3485</span><span id="line-3485">     * CP prePut()/preDelete()/preIncrement()/preAppend() hooks for all mutations in a batch. This</span>
+<span class="source-line-no">3486</span><span id="line-3486">     * is intended to operate on entire batch and will be called from outside of class to check and</span>
+<span class="source-line-no">3487</span><span id="line-3487">     * prepare batch. This can be implemented by calling helper method</span>
+<span class="source-line-no">3488</span><span id="line-3488">     * {@link #checkAndPrepareMutation(int, long)} in a 'for' loop over mutations.</span>
+<span class="source-line-no">3489</span><span id="line-3489">     */</span>
+<span class="source-line-no">3490</span><span id="line-3490">    public abstract void checkAndPrepare() throws IOException;</span>
+<span class="source-line-no">3491</span><span id="line-3491"></span>
+<span class="source-line-no">3492</span><span id="line-3492">    /**</span>
+<span class="source-line-no">3493</span><span id="line-3493">     * Implement any Put request specific check and prepare logic here. Please refer to</span>
+<span class="source-line-no">3494</span><span id="line-3494">     * {@link #checkAndPrepareMutation(Mutation, long)} for how its used.</span>
+<span class="source-line-no">3495</span><span id="line-3495">     */</span>
+<span class="source-line-no">3496</span><span id="line-3496">    protected abstract void checkAndPreparePut(final Put p) throws IOException;</span>
+<span class="source-line-no">3497</span><span id="line-3497"></span>
+<span class="source-line-no">3498</span><span id="line-3498">    /**</span>
+<span class="source-line-no">3499</span><span id="line-3499">     * If necessary, calls preBatchMutate() CP hook for a mini-batch and updates metrics, cell</span>
+<span class="source-line-no">3500</span><span id="line-3500">     * count, tags and timestamp for all cells of all operations in a mini-batch.</span>
+<span class="source-line-no">3501</span><span id="line-3501">     */</span>
+<span class="source-line-no">3502</span><span id="line-3502">    public abstract void prepareMiniBatchOperations(</span>
+<span class="source-line-no">3503</span><span id="line-3503">      MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, long timestamp,</span>
+<span class="source-line-no">3504</span><span id="line-3504">      final List&lt;RowLock&gt; acquiredRowLocks) throws IOException;</span>
+<span class="source-line-no">3505</span><span id="line-3505"></span>
+<span class="source-line-no">3506</span><span id="line-3506">    /**</span>
+<span class="source-line-no">3507</span><span id="line-3507">     * Write mini-batch operations to MemStore</span>
+<span class="source-line-no">3508</span><span id="line-3508">     */</span>
+<span class="source-line-no">3509</span><span id="line-3509">    public abstract WriteEntry writeMiniBatchOperationsToMemStore(</span>
+<span class="source-line-no">3510</span><span id="line-3510">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry,</span>
+<span class="source-line-no">3511</span><span id="line-3511">      long now) throws IOException;</span>
+<span class="source-line-no">3512</span><span id="line-3512"></span>
+<span class="source-line-no">3513</span><span id="line-3513">    protected void writeMiniBatchOperationsToMemStore(</span>
+<span class="source-line-no">3514</span><span id="line-3514">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final long writeNumber)</span>
+<span class="source-line-no">3515</span><span id="line-3515">      throws IOException {</span>
+<span class="source-line-no">3516</span><span id="line-3516">      MemStoreSizing memStoreAccounting = new NonThreadSafeMemStoreSizing();</span>
+<span class="source-line-no">3517</span><span id="line-3517">      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {</span>
+<span class="source-line-no">3518</span><span id="line-3518">        // We need to update the sequence id for following reasons.</span>
+<span class="source-line-no">3519</span><span id="line-3519">        // 1) If the op is in replay mode, FSWALEntry#stampRegionSequenceId won't stamp sequence id.</span>
+<span class="source-line-no">3520</span><span id="line-3520">        // 2) If no WAL, FSWALEntry won't be used</span>
+<span class="source-line-no">3521</span><span id="line-3521">        // we use durability of the original mutation for the mutation passed by CP.</span>
+<span class="source-line-no">3522</span><span id="line-3522">        if (isInReplay() || getMutation(index).getDurability() == Durability.SKIP_WAL) {</span>
+<span class="source-line-no">3523</span><span id="line-3523">          region.updateSequenceId(familyCellMaps[index].values(), writeNumber);</span>
+<span class="source-line-no">3524</span><span id="line-3524">        }</span>
+<span class="source-line-no">3525</span><span id="line-3525">        applyFamilyMapToMemStore(familyCellMaps[index], memStoreAccounting);</span>
+<span class="source-line-no">3526</span><span id="line-3526">        return true;</span>
+<span class="source-line-no">3527</span><span id="line-3527">      });</span>
+<span class="source-line-no">3528</span><span id="line-3528">      // update memStore size</span>
+<span class="source-line-no">3529</span><span id="line-3529">      region.incMemStoreSize(memStoreAccounting.getDataSize(), memStoreAccounting.getHeapSize(),</span>
+<span class="source-line-no">3530</span><span id="line-3530">        memStoreAccounting.getOffHeapSize(), memStoreAccounting.getCellsCount());</span>
+<span class="source-line-no">3531</span><span id="line-3531">    }</span>
+<span class="source-line-no">3532</span><span id="line-3532"></span>
+<span class="source-line-no">3533</span><span id="line-3533">    public boolean isDone() {</span>
+<span class="source-line-no">3534</span><span id="line-3534">      return nextIndexToProcess == operations.length;</span>
+<span class="source-line-no">3535</span><span id="line-3535">    }</span>
+<span class="source-line-no">3536</span><span id="line-3536"></span>
+<span class="source-line-no">3537</span><span id="line-3537">    public int size() {</span>
+<span class="source-line-no">3538</span><span id="line-3538">      return operations.length;</span>
+<span class="source-line-no">3539</span><span id="line-3539">    }</span>
+<span class="source-line-no">3540</span><span id="line-3540"></span>
+<span class="source-line-no">3541</span><span id="line-3541">    public boolean isOperationPending(int index) {</span>
+<span class="source-line-no">3542</span><span id="line-3542">      return retCodeDetails[index].getOperationStatusCode() == OperationStatusCode.NOT_RUN;</span>
+<span class="source-line-no">3543</span><span id="line-3543">    }</span>
+<span class="source-line-no">3544</span><span id="line-3544"></span>
+<span class="source-line-no">3545</span><span id="line-3545">    public List&lt;UUID&gt; getClusterIds() {</span>
+<span class="source-line-no">3546</span><span id="line-3546">      assert size() != 0;</span>
+<span class="source-line-no">3547</span><span id="line-3547">      return getMutation(0).getClusterIds();</span>
+<span class="source-line-no">3548</span><span id="line-3548">    }</span>
+<span class="source-line-no">3549</span><span id="line-3549"></span>
+<span class="source-line-no">3550</span><span id="line-3550">    boolean isAtomic() {</span>
+<span class="source-line-no">3551</span><span id="line-3551">      return atomic;</span>
+<span class="source-line-no">3552</span><span id="line-3552">    }</span>
+<span class="source-line-no">3553</span><span id="line-3553"></span>
+<span class="source-line-no">3554</span><span id="line-3554">    /**</span>
+<span class="source-line-no">3555</span><span id="line-3555">     * Helper method that checks and prepares only one mutation. This can be used to implement</span>
+<span class="source-line-no">3556</span><span id="line-3556">     * {@link #checkAndPrepare()} for entire Batch. NOTE: As CP</span>
+<span class="source-line-no">3557</span><span id="line-3557">     * prePut()/preDelete()/preIncrement()/preAppend() hooks may modify mutations, this method</span>
+<span class="source-line-no">3558</span><span id="line-3558">     * should be called after prePut()/preDelete()/preIncrement()/preAppend() CP hooks are run for</span>
+<span class="source-line-no">3559</span><span id="line-3559">     * the mutation</span>
+<span class="source-line-no">3560</span><span id="line-3560">     */</span>
+<span class="source-line-no">3561</span><span id="line-3561">    protected void checkAndPrepareMutation(Mutation mutation, final long timestamp)</span>
+<span class="source-line-no">3562</span><span id="line-3562">      throws IOException {</span>
+<span class="source-line-no">3563</span><span id="line-3563">      region.checkRow(mutation.getRow(), "batchMutate");</span>
+<span class="source-line-no">3564</span><span id="line-3564">      if (mutation instanceof Put) {</span>
+<span class="source-line-no">3565</span><span id="line-3565">        // Check the families in the put. If bad, skip this one.</span>
+<span class="source-line-no">3566</span><span id="line-3566">        checkAndPreparePut((Put) mutation);</span>
+<span class="source-line-no">3567</span><span id="line-3567">        region.checkTimestamps(mutation.getFamilyCellMap(), timestamp);</span>
+<span class="source-line-no">3568</span><span id="line-3568">      } else if (mutation instanceof Delete) {</span>
+<span class="source-line-no">3569</span><span id="line-3569">        region.prepareDelete((Delete) mutation);</span>
+<span class="source-line-no">3570</span><span id="line-3570">      } else if (mutation instanceof Increment || mutation instanceof Append) {</span>
+<span class="source-line-no">3571</span><span id="line-3571">        region.checkFamilies(mutation.getFamilyCellMap().keySet(), mutation.getDurability());</span>
+<span class="source-line-no">3572</span><span id="line-3572">      }</span>
+<span class="source-line-no">3573</span><span id="line-3573">    }</span>
+<span class="source-line-no">3574</span><span id="line-3574"></span>
+<span class="source-line-no">3575</span><span id="line-3575">    protected void checkAndPrepareMutation(int index, long timestamp) throws IOException {</span>
+<span class="source-line-no">3576</span><span id="line-3576">      Mutation mutation = getMutation(index);</span>
+<span class="source-line-no">3577</span><span id="line-3577">      try {</span>
+<span class="source-line-no">3578</span><span id="line-3578">        this.checkAndPrepareMutation(mutation, timestamp);</span>
+<span class="source-line-no">3579</span><span id="line-3579"></span>
+<span class="source-line-no">3580</span><span id="line-3580">        if (mutation instanceof Put || mutation instanceof Delete) {</span>
+<span class="source-line-no">3581</span><span id="line-3581">          // store the family map reference to allow for mutations</span>
+<span class="source-line-no">3582</span><span id="line-3582">          // we know that in mutation, only ExtendedCells are allow so here we do a fake cast, to</span>
+<span class="source-line-no">3583</span><span id="line-3583">          // simplify later logic</span>
+<span class="source-line-no">3584</span><span id="line-3584">          familyCellMaps[index] = ClientInternalHelper.getExtendedFamilyCellMap(mutation);</span>
+<span class="source-line-no">3585</span><span id="line-3585">        }</span>
+<span class="source-line-no">3586</span><span id="line-3586"></span>
+<span class="source-line-no">3587</span><span id="line-3587">        // store durability for the batch (highest durability of all operations in the batch)</span>
+<span class="source-line-no">3588</span><span id="line-3588">        Durability tmpDur = region.getEffectiveDurability(mutation.getDurability());</span>
+<span class="source-line-no">3589</span><span id="line-3589">        if (tmpDur.ordinal() &gt; durability.ordinal()) {</span>
+<span class="source-line-no">3590</span><span id="line-3590">          durability = tmpDur;</span>
+<span class="source-line-no">3591</span><span id="line-3591">        }</span>
+<span class="source-line-no">3592</span><span id="line-3592">      } catch (NoSuchColumnFamilyException nscfe) {</span>
+<span class="source-line-no">3593</span><span id="line-3593">        final String msg = "No such column family in batch mutation in region " + this;</span>
+<span class="source-line-no">3594</span><span id="line-3594">        if (observedExceptions.hasSeenNoSuchFamily()) {</span>
+<span class="source-line-no">3595</span><span id="line-3595">          LOG.warn(msg + nscfe.getMessage());</span>
+<span class="source-line-no">3596</span><span id="line-3596">        } else {</span>
+<span class="source-line-no">3597</span><span id="line-3597">          LOG.warn(msg, nscfe);</span>
+<span class="source-line-no">3598</span><span id="line-3598">          observedExceptions.sawNoSuchFamily();</span>
+<span class="source-line-no">3599</span><span id="line-3599">        }</span>
+<span class="source-line-no">3600</span><span id="line-3600">        retCodeDetails[index] =</span>
+<span class="source-line-no">3601</span><span id="line-3601">          new OperationStatus(OperationStatusCode.BAD_FAMILY, nscfe.getMessage());</span>
+<span class="source-line-no">3602</span><span id="line-3602">        if (isAtomic()) { // fail, atomic means all or none</span>
+<span class="source-line-no">3603</span><span id="line-3603">          throw nscfe;</span>
+<span class="source-line-no">3604</span><span id="line-3604">        }</span>
+<span class="source-line-no">3605</span><span id="line-3605">      } catch (FailedSanityCheckException fsce) {</span>
+<span class="source-line-no">3606</span><span id="line-3606">        final String msg = "Batch Mutation did not pass sanity check in region " + this;</span>
+<span class="source-line-no">3607</span><span id="line-3607">        if (observedExceptions.hasSeenFailedSanityCheck()) {</span>
+<span class="source-line-no">3608</span><span id="line-3608">          LOG.warn(msg + fsce.getMessage());</span>
+<span class="source-line-no">3609</span><span id="line-3609">        } else {</span>
+<span class="source-line-no">3610</span><span id="line-3610">          LOG.warn(msg, fsce);</span>
+<span class="source-line-no">3611</span><span id="line-3611">          observedExceptions.sawFailedSanityCheck();</span>
 <span class="source-line-no">3612</span><span id="line-3612">        }</span>
-<span class="source-line-no">3613</span><span id="line-3613"></span>
-<span class="source-line-no">3614</span><span id="line-3614">        Mutation mutation = getMutation(lastIndexExclusive);</span>
-<span class="source-line-no">3615</span><span id="line-3615">        // If we haven't got any rows in our batch, we should block to get the next one.</span>
-<span class="source-line-no">3616</span><span id="line-3616">        RowLock rowLock = null;</span>
-<span class="source-line-no">3617</span><span id="line-3617">        boolean throwException = false;</span>
-<span class="source-line-no">3618</span><span id="line-3618">        try {</span>
-<span class="source-line-no">3619</span><span id="line-3619">          // if atomic then get exclusive lock, else shared lock</span>
-<span class="source-line-no">3620</span><span id="line-3620">          rowLock = region.getRowLock(mutation.getRow(), !isAtomic(), prevRowLock);</span>
-<span class="source-line-no">3621</span><span id="line-3621">        } catch (TimeoutIOException | InterruptedIOException e) {</span>
-<span class="source-line-no">3622</span><span id="line-3622">          // NOTE: We will retry when other exceptions, but we should stop if we receive</span>
-<span class="source-line-no">3623</span><span id="line-3623">          // TimeoutIOException or InterruptedIOException as operation has timed out or</span>
-<span class="source-line-no">3624</span><span id="line-3624">          // interrupted respectively.</span>
-<span class="source-line-no">3625</span><span id="line-3625">          throwException = true;</span>
-<span class="source-line-no">3626</span><span id="line-3626">          throw e;</span>
-<span class="source-line-no">3627</span><span id="line-3627">        } catch (IOException ioe) {</span>
-<span class="source-line-no">3628</span><span id="line-3628">          LOG.warn("Failed getting lock, row={}, in region {}",</span>
-<span class="source-line-no">3629</span><span id="line-3629">            Bytes.toStringBinary(mutation.getRow()), this, ioe);</span>
-<span class="source-line-no">3630</span><span id="line-3630">          if (isAtomic()) { // fail, atomic means all or none</span>
-<span class="source-line-no">3631</span><span id="line-3631">            throwException = true;</span>
-<span class="source-line-no">3632</span><span id="line-3632">            throw ioe;</span>
-<span class="source-line-no">3633</span><span id="line-3633">          }</span>
-<span class="source-line-no">3634</span><span id="line-3634">        } catch (Throwable throwable) {</span>
-<span class="source-line-no">3635</span><span id="line-3635">          throwException = true;</span>
-<span class="source-line-no">3636</span><span id="line-3636">          throw throwable;</span>
-<span class="source-line-no">3637</span><span id="line-3637">        } finally {</span>
-<span class="source-line-no">3638</span><span id="line-3638">          if (throwException) {</span>
-<span class="source-line-no">3639</span><span id="line-3639">            region.storeHotnessProtector.finish(curFamilyCellMap);</span>
-<span class="source-line-no">3640</span><span id="line-3640">          }</span>
-<span class="source-line-no">3641</span><span id="line-3641">        }</span>
-<span class="source-line-no">3642</span><span id="line-3642">        if (rowLock == null) {</span>
-<span class="source-line-no">3643</span><span id="line-3643">          // We failed to grab another lock</span>
-<span class="source-line-no">3644</span><span id="line-3644">          if (isAtomic()) {</span>
-<span class="source-line-no">3645</span><span id="line-3645">            region.storeHotnessProtector.finish(curFamilyCellMap);</span>
-<span class="source-line-no">3646</span><span id="line-3646">            throw new IOException("Can't apply all operations atomically!");</span>
-<span class="source-line-no">3647</span><span id="line-3647">          }</span>
-<span class="source-line-no">3648</span><span id="line-3648">          break; // Stop acquiring more rows for this batch</span>
-<span class="source-line-no">3649</span><span id="line-3649">        } else {</span>
-<span class="source-line-no">3650</span><span id="line-3650">          if (rowLock != prevRowLock) {</span>
-<span class="source-line-no">3651</span><span id="line-3651">            // It is a different row now, add this to the acquiredRowLocks and</span>
-<span class="source-line-no">3652</span><span id="line-3652">            // set prevRowLock to the new returned rowLock</span>
-<span class="source-line-no">3653</span><span id="line-3653">            acquiredRowLocks.add(rowLock);</span>
-<span class="source-line-no">3654</span><span id="line-3654">            prevRowLock = rowLock;</span>
-<span class="source-line-no">3655</span><span id="line-3655">          }</span>
-<span class="source-line-no">3656</span><span id="line-3656">        }</span>
-<span class="source-line-no">3657</span><span id="line-3657"></span>
-<span class="source-line-no">3658</span><span id="line-3658">        readyToWriteCount++;</span>
-<span class="source-line-no">3659</span><span id="line-3659">      }</span>
-<span class="source-line-no">3660</span><span id="line-3660">      return createMiniBatch(lastIndexExclusive, readyToWriteCount);</span>
-<span class="source-line-no">3661</span><span id="line-3661">    }</span>
-<span class="source-line-no">3662</span><span id="line-3662"></span>
-<span class="source-line-no">3663</span><span id="line-3663">    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,</span>
-<span class="source-line-no">3664</span><span id="line-3664">      final int readyToWriteCount) {</span>
-<span class="source-line-no">3665</span><span id="line-3665">      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,</span>
-<span class="source-line-no">3666</span><span id="line-3666">        walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);</span>
-<span class="source-line-no">3667</span><span id="line-3667">    }</span>
-<span class="source-line-no">3668</span><span id="line-3668"></span>
-<span class="source-line-no">3669</span><span id="line-3669">    protected WALEdit createWALEdit(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {</span>
-<span class="source-line-no">3670</span><span id="line-3670">      return new WALEdit(miniBatchOp.getCellCount(), isInReplay());</span>
-<span class="source-line-no">3671</span><span id="line-3671">    }</span>
-<span class="source-line-no">3672</span><span id="line-3672"></span>
-<span class="source-line-no">3673</span><span id="line-3673">    /**</span>
-<span class="source-line-no">3674</span><span id="line-3674">     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are</span>
-<span class="source-line-no">3675</span><span id="line-3675">     * present, they are merged to result WALEdit.</span>
-<span class="source-line-no">3676</span><span id="line-3676">     */</span>
-<span class="source-line-no">3677</span><span id="line-3677">    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt;</span>
-<span class="source-line-no">3678</span><span id="line-3678">      buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {</span>
-<span class="source-line-no">3679</span><span id="line-3679">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();</span>
-<span class="source-line-no">3680</span><span id="line-3680"></span>
-<span class="source-line-no">3681</span><span id="line-3681">      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {</span>
-<span class="source-line-no">3682</span><span id="line-3682">        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;</span>
-<span class="source-line-no">3683</span><span id="line-3683"></span>
-<span class="source-line-no">3684</span><span id="line-3684">        @Override</span>
-<span class="source-line-no">3685</span><span id="line-3685">        public boolean visit(int index) throws IOException {</span>
-<span class="source-line-no">3686</span><span id="line-3686">          Mutation m = getMutation(index);</span>
-<span class="source-line-no">3687</span><span id="line-3687">          // we use durability of the original mutation for the mutation passed by CP.</span>
-<span class="source-line-no">3688</span><span id="line-3688">          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {</span>
-<span class="source-line-no">3689</span><span id="line-3689">            region.recordMutationWithoutWal(m.getFamilyCellMap());</span>
-<span class="source-line-no">3690</span><span id="line-3690">            /**</span>
-<span class="source-line-no">3691</span><span id="line-3691">             * Here is for HBASE-26993,in order to make the new framework for region replication</span>
-<span class="source-line-no">3692</span><span id="line-3692">             * could work for SKIP_WAL, we save the {@link Mutation} which</span>
-<span class="source-line-no">3693</span><span id="line-3693">             * {@link Mutation#getDurability} is {@link Durability#SKIP_WAL} in miniBatchOp.</span>
-<span class="source-line-no">3694</span><span id="line-3694">             */</span>
-<span class="source-line-no">3695</span><span id="line-3695">            cacheSkipWALMutationForRegionReplication(miniBatchOp, walEdits, familyCellMaps[index]);</span>
-<span class="source-line-no">3696</span><span id="line-3696">            return true;</span>
-<span class="source-line-no">3697</span><span id="line-3697">          }</span>
-<span class="source-line-no">3698</span><span id="line-3698"></span>
-<span class="source-line-no">3699</span><span id="line-3699">          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.</span>
-<span class="source-line-no">3700</span><span id="line-3700">          // Given how nonce keys are originally written, these should be contiguous.</span>
-<span class="source-line-no">3701</span><span id="line-3701">          // They don't have to be, it will still work, just write more WALEdits than needed.</span>
-<span class="source-line-no">3702</span><span id="line-3702">          long nonceGroup = getNonceGroup(index);</span>
-<span class="source-line-no">3703</span><span id="line-3703">          long nonce = getNonce(index);</span>
-<span class="source-line-no">3704</span><span id="line-3704">          if (</span>
-<span class="source-line-no">3705</span><span id="line-3705">            curWALEditForNonce == null</span>
-<span class="source-line-no">3706</span><span id="line-3706">              || curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup</span>
-<span class="source-line-no">3707</span><span id="line-3707">              || curWALEditForNonce.getFirst().getNonce() != nonce</span>
-<span class="source-line-no">3708</span><span id="line-3708">          ) {</span>
-<span class="source-line-no">3709</span><span id="line-3709">            curWALEditForNonce =</span>
-<span class="source-line-no">3710</span><span id="line-3710">              new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce), createWALEdit(miniBatchOp));</span>
-<span class="source-line-no">3711</span><span id="line-3711">            walEdits.add(curWALEditForNonce);</span>
-<span class="source-line-no">3712</span><span id="line-3712">          }</span>
-<span class="source-line-no">3713</span><span id="line-3713">          WALEdit walEdit = curWALEditForNonce.getSecond();</span>
-<span class="source-line-no">3714</span><span id="line-3714"></span>
-<span class="source-line-no">3715</span><span id="line-3715">          // Add WAL edits from CPs.</span>
-<span class="source-line-no">3716</span><span id="line-3716">          WALEdit fromCP = walEditsFromCoprocessors[index];</span>
-<span class="source-line-no">3717</span><span id="line-3717">          List&lt;ExtendedCell&gt; cellsFromCP = fromCP == null</span>
-<span class="source-line-no">3718</span><span id="line-3718">            ? Collections.emptyList()</span>
-<span class="source-line-no">3719</span><span id="line-3719">            : WALEditInternalHelper.getExtendedCells(fromCP);</span>
-<span class="source-line-no">3720</span><span id="line-3720">          addNonSkipWALMutationsToWALEdit(miniBatchOp, walEdit, cellsFromCP, familyCellMaps[index]);</span>
-<span class="source-line-no">3721</span><span id="line-3721">          return true;</span>
-<span class="source-line-no">3722</span><span id="line-3722">        }</span>
-<span class="source-line-no">3723</span><span id="line-3723">      });</span>
-<span class="source-line-no">3724</span><span id="line-3724">      return walEdits;</span>
-<span class="source-line-no">3725</span><span id="line-3725">    }</span>
-<span class="source-line-no">3726</span><span id="line-3726"></span>
-<span class="source-line-no">3727</span><span id="line-3727">    protected void addNonSkipWALMutationsToWALEdit(</span>
-<span class="source-line-no">3728</span><span id="line-3728">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, WALEdit walEdit,</span>
-<span class="source-line-no">3729</span><span id="line-3729">      List&lt;ExtendedCell&gt; cellsFromCP, Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
-<span class="source-line-no">3730</span><span id="line-3730">      doAddCellsToWALEdit(walEdit, cellsFromCP, familyCellMap);</span>
-<span class="source-line-no">3731</span><span id="line-3731">    }</span>
-<span class="source-line-no">3732</span><span id="line-3732"></span>
-<span class="source-line-no">3733</span><span id="line-3733">    protected static void doAddCellsToWALEdit(WALEdit walEdit, List&lt;ExtendedCell&gt; cellsFromCP,</span>
-<span class="source-line-no">3734</span><span id="line-3734">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
-<span class="source-line-no">3735</span><span id="line-3735">      WALEditInternalHelper.addExtendedCell(walEdit, cellsFromCP);</span>
-<span class="source-line-no">3736</span><span id="line-3736">      WALEditInternalHelper.addMap(walEdit, familyCellMap);</span>
-<span class="source-line-no">3737</span><span id="line-3737">    }</span>
-<span class="source-line-no">3738</span><span id="line-3738"></span>
-<span class="source-line-no">3739</span><span id="line-3739">    protected abstract void cacheSkipWALMutationForRegionReplication(</span>
-<span class="source-line-no">3740</span><span id="line-3740">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
-<span class="source-line-no">3741</span><span id="line-3741">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits, Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap);</span>
-<span class="source-line-no">3742</span><span id="line-3742"></span>
-<span class="source-line-no">3743</span><span id="line-3743">    /**</span>
-<span class="source-line-no">3744</span><span id="line-3744">     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if</span>
-<span class="source-line-no">3745</span><span id="line-3745">     * required) and completing mvcc.</span>
-<span class="source-line-no">3746</span><span id="line-3746">     */</span>
-<span class="source-line-no">3747</span><span id="line-3747">    public void completeMiniBatchOperations(</span>
-<span class="source-line-no">3748</span><span id="line-3748">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)</span>
-<span class="source-line-no">3749</span><span id="line-3749">      throws IOException {</span>
-<span class="source-line-no">3750</span><span id="line-3750">      if (writeEntry != null) {</span>
-<span class="source-line-no">3751</span><span id="line-3751">        region.mvcc.completeAndWait(writeEntry);</span>
-<span class="source-line-no">3752</span><span id="line-3752">      }</span>
-<span class="source-line-no">3753</span><span id="line-3753">    }</span>
-<span class="source-line-no">3754</span><span id="line-3754"></span>
-<span class="source-line-no">3755</span><span id="line-3755">    public void doPostOpCleanupForMiniBatch(</span>
-<span class="source-line-no">3756</span><span id="line-3756">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,</span>
-<span class="source-line-no">3757</span><span id="line-3757">      boolean success) throws IOException {</span>
-<span class="source-line-no">3758</span><span id="line-3758">      doFinishHotnessProtector(miniBatchOp);</span>
-<span class="source-line-no">3759</span><span id="line-3759">    }</span>
-<span class="source-line-no">3760</span><span id="line-3760"></span>
-<span class="source-line-no">3761</span><span id="line-3761">    private void</span>
-<span class="source-line-no">3762</span><span id="line-3762">      doFinishHotnessProtector(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {</span>
-<span class="source-line-no">3763</span><span id="line-3763">      // check and return if the protector is not enabled</span>
-<span class="source-line-no">3764</span><span id="line-3764">      if (!region.storeHotnessProtector.isEnable()) {</span>
-<span class="source-line-no">3765</span><span id="line-3765">        return;</span>
-<span class="source-line-no">3766</span><span id="line-3766">      }</span>
-<span class="source-line-no">3767</span><span id="line-3767">      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.</span>
-<span class="source-line-no">3768</span><span id="line-3768">      // This case was handled.</span>
-<span class="source-line-no">3769</span><span id="line-3769">      if (miniBatchOp == null) {</span>
-<span class="source-line-no">3770</span><span id="line-3770">        return;</span>
-<span class="source-line-no">3771</span><span id="line-3771">      }</span>
-<span class="source-line-no">3772</span><span id="line-3772"></span>
-<span class="source-line-no">3773</span><span id="line-3773">      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();</span>
-<span class="source-line-no">3774</span><span id="line-3774"></span>
-<span class="source-line-no">3775</span><span id="line-3775">      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {</span>
-<span class="source-line-no">3776</span><span id="line-3776">        switch (retCodeDetails[i].getOperationStatusCode()) {</span>
-<span class="source-line-no">3777</span><span id="line-3777">          case SUCCESS:</span>
-<span class="source-line-no">3778</span><span id="line-3778">          case FAILURE:</span>
-<span class="source-line-no">3779</span><span id="line-3779">            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());</span>
-<span class="source-line-no">3780</span><span id="line-3780">            break;</span>
-<span class="source-line-no">3781</span><span id="line-3781">          default:</span>
-<span class="source-line-no">3782</span><span id="line-3782">            // do nothing</span>
-<span class="source-line-no">3783</span><span id="line-3783">            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the</span>
-<span class="source-line-no">3784</span><span id="line-3784">            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start</span>
-<span class="source-line-no">3785</span><span id="line-3785">            break;</span>
-<span class="source-line-no">3786</span><span id="line-3786">        }</span>
-<span class="source-line-no">3787</span><span id="line-3787">      }</span>
+<span class="source-line-no">3613</span><span id="line-3613">        retCodeDetails[index] =</span>
+<span class="source-line-no">3614</span><span id="line-3614">          new OperationStatus(OperationStatusCode.SANITY_CHECK_FAILURE, fsce.getMessage());</span>
+<span class="source-line-no">3615</span><span id="line-3615">        if (isAtomic()) {</span>
+<span class="source-line-no">3616</span><span id="line-3616">          throw fsce;</span>
+<span class="source-line-no">3617</span><span id="line-3617">        }</span>
+<span class="source-line-no">3618</span><span id="line-3618">      } catch (WrongRegionException we) {</span>
+<span class="source-line-no">3619</span><span id="line-3619">        final String msg = "Batch mutation had a row that does not belong to this region " + this;</span>
+<span class="source-line-no">3620</span><span id="line-3620">        if (observedExceptions.hasSeenWrongRegion()) {</span>
+<span class="source-line-no">3621</span><span id="line-3621">          LOG.warn(msg + we.getMessage());</span>
+<span class="source-line-no">3622</span><span id="line-3622">        } else {</span>
+<span class="source-line-no">3623</span><span id="line-3623">          LOG.warn(msg, we);</span>
+<span class="source-line-no">3624</span><span id="line-3624">          observedExceptions.sawWrongRegion();</span>
+<span class="source-line-no">3625</span><span id="line-3625">        }</span>
+<span class="source-line-no">3626</span><span id="line-3626">        retCodeDetails[index] =</span>
+<span class="source-line-no">3627</span><span id="line-3627">          new OperationStatus(OperationStatusCode.SANITY_CHECK_FAILURE, we.getMessage());</span>
+<span class="source-line-no">3628</span><span id="line-3628">        if (isAtomic()) {</span>
+<span class="source-line-no">3629</span><span id="line-3629">          throw we;</span>
+<span class="source-line-no">3630</span><span id="line-3630">        }</span>
+<span class="source-line-no">3631</span><span id="line-3631">      }</span>
+<span class="source-line-no">3632</span><span id="line-3632">    }</span>
+<span class="source-line-no">3633</span><span id="line-3633"></span>
+<span class="source-line-no">3634</span><span id="line-3634">    /**</span>
+<span class="source-line-no">3635</span><span id="line-3635">     * Creates Mini-batch of all operations [nextIndexToProcess, lastIndexExclusive) for which a row</span>
+<span class="source-line-no">3636</span><span id="line-3636">     * lock can be acquired. All mutations with locked rows are considered to be In-progress</span>
+<span class="source-line-no">3637</span><span id="line-3637">     * operations and hence the name {@link MiniBatchOperationInProgress}. Mini batch is window over</span>
+<span class="source-line-no">3638</span><span id="line-3638">     * {@link BatchOperation} and contains contiguous pending operations.</span>
+<span class="source-line-no">3639</span><span id="line-3639">     * @param acquiredRowLocks keeps track of rowLocks acquired.</span>
+<span class="source-line-no">3640</span><span id="line-3640">     */</span>
+<span class="source-line-no">3641</span><span id="line-3641">    public MiniBatchOperationInProgress&lt;Mutation&gt;</span>
+<span class="source-line-no">3642</span><span id="line-3642">      lockRowsAndBuildMiniBatch(List&lt;RowLock&gt; acquiredRowLocks) throws IOException {</span>
+<span class="source-line-no">3643</span><span id="line-3643">      int readyToWriteCount = 0;</span>
+<span class="source-line-no">3644</span><span id="line-3644">      int lastIndexExclusive = 0;</span>
+<span class="source-line-no">3645</span><span id="line-3645">      RowLock prevRowLock = null;</span>
+<span class="source-line-no">3646</span><span id="line-3646">      for (; lastIndexExclusive &lt; size(); lastIndexExclusive++) {</span>
+<span class="source-line-no">3647</span><span id="line-3647">        // It reaches the miniBatchSize, stop here and process the miniBatch</span>
+<span class="source-line-no">3648</span><span id="line-3648">        // This only applies to non-atomic batch operations.</span>
+<span class="source-line-no">3649</span><span id="line-3649">        if (!isAtomic() &amp;&amp; (readyToWriteCount == region.miniBatchSize)) {</span>
+<span class="source-line-no">3650</span><span id="line-3650">          break;</span>
+<span class="source-line-no">3651</span><span id="line-3651">        }</span>
+<span class="source-line-no">3652</span><span id="line-3652"></span>
+<span class="source-line-no">3653</span><span id="line-3653">        if (!isOperationPending(lastIndexExclusive)) {</span>
+<span class="source-line-no">3654</span><span id="line-3654">          continue;</span>
+<span class="source-line-no">3655</span><span id="line-3655">        }</span>
+<span class="source-line-no">3656</span><span id="line-3656"></span>
+<span class="source-line-no">3657</span><span id="line-3657">        // HBASE-19389 Limit concurrency of put with dense (hundreds) columns to avoid exhausting</span>
+<span class="source-line-no">3658</span><span id="line-3658">        // RS handlers, covering both MutationBatchOperation and ReplayBatchOperation</span>
+<span class="source-line-no">3659</span><span id="line-3659">        // The BAD_FAMILY/SANITY_CHECK_FAILURE cases are handled in checkAndPrepare phase and won't</span>
+<span class="source-line-no">3660</span><span id="line-3660">        // pass the isOperationPending check</span>
+<span class="source-line-no">3661</span><span id="line-3661">        Map&lt;byte[], List&lt;Cell&gt;&gt; curFamilyCellMap =</span>
+<span class="source-line-no">3662</span><span id="line-3662">          getMutation(lastIndexExclusive).getFamilyCellMap();</span>
+<span class="source-line-no">3663</span><span id="line-3663">        try {</span>
+<span class="source-line-no">3664</span><span id="line-3664">          // start the protector before acquiring row lock considering performance, and will finish</span>
+<span class="source-line-no">3665</span><span id="line-3665">          // it when encountering exception</span>
+<span class="source-line-no">3666</span><span id="line-3666">          region.storeHotnessProtector.start(curFamilyCellMap);</span>
+<span class="source-line-no">3667</span><span id="line-3667">        } catch (RegionTooBusyException rtbe) {</span>
+<span class="source-line-no">3668</span><span id="line-3668">          region.storeHotnessProtector.finish(curFamilyCellMap);</span>
+<span class="source-line-no">3669</span><span id="line-3669">          if (isAtomic()) {</span>
+<span class="source-line-no">3670</span><span id="line-3670">            throw rtbe;</span>
+<span class="source-line-no">3671</span><span id="line-3671">          }</span>
+<span class="source-line-no">3672</span><span id="line-3672">          retCodeDetails[lastIndexExclusive] =</span>
+<span class="source-line-no">3673</span><span id="line-3673">            new OperationStatus(OperationStatusCode.STORE_TOO_BUSY, rtbe.getMessage());</span>
+<span class="source-line-no">3674</span><span id="line-3674">          continue;</span>
+<span class="source-line-no">3675</span><span id="line-3675">        }</span>
+<span class="source-line-no">3676</span><span id="line-3676"></span>
+<span class="source-line-no">3677</span><span id="line-3677">        Mutation mutation = getMutation(lastIndexExclusive);</span>
+<span class="source-line-no">3678</span><span id="line-3678">        // If we haven't got any rows in our batch, we should block to get the next one.</span>
+<span class="source-line-no">3679</span><span id="line-3679">        RowLock rowLock = null;</span>
+<span class="source-line-no">3680</span><span id="line-3680">        boolean throwException = false;</span>
+<span class="source-line-no">3681</span><span id="line-3681">        try {</span>
+<span class="source-line-no">3682</span><span id="line-3682">          // if atomic then get exclusive lock, else shared lock</span>
+<span class="source-line-no">3683</span><span id="line-3683">          rowLock = region.getRowLock(mutation.getRow(), !isAtomic(), prevRowLock);</span>
+<span class="source-line-no">3684</span><span id="line-3684">        } catch (TimeoutIOException | InterruptedIOException e) {</span>
+<span class="source-line-no">3685</span><span id="line-3685">          // NOTE: We will retry when other exceptions, but we should stop if we receive</span>
+<span class="source-line-no">3686</span><span id="line-3686">          // TimeoutIOException or InterruptedIOException as operation has timed out or</span>
+<span class="source-line-no">3687</span><span id="line-3687">          // interrupted respectively.</span>
+<span class="source-line-no">3688</span><span id="line-3688">          throwException = true;</span>
+<span class="source-line-no">3689</span><span id="line-3689">          throw e;</span>
+<span class="source-line-no">3690</span><span id="line-3690">        } catch (IOException ioe) {</span>
+<span class="source-line-no">3691</span><span id="line-3691">          LOG.warn("Failed getting lock, row={}, in region {}",</span>
+<span class="source-line-no">3692</span><span id="line-3692">            Bytes.toStringBinary(mutation.getRow()), this, ioe);</span>
+<span class="source-line-no">3693</span><span id="line-3693">          if (isAtomic()) { // fail, atomic means all or none</span>
+<span class="source-line-no">3694</span><span id="line-3694">            throwException = true;</span>
+<span class="source-line-no">3695</span><span id="line-3695">            throw ioe;</span>
+<span class="source-line-no">3696</span><span id="line-3696">          }</span>
+<span class="source-line-no">3697</span><span id="line-3697">        } catch (Throwable throwable) {</span>
+<span class="source-line-no">3698</span><span id="line-3698">          throwException = true;</span>
+<span class="source-line-no">3699</span><span id="line-3699">          throw throwable;</span>
+<span class="source-line-no">3700</span><span id="line-3700">        } finally {</span>
+<span class="source-line-no">3701</span><span id="line-3701">          if (throwException) {</span>
+<span class="source-line-no">3702</span><span id="line-3702">            region.storeHotnessProtector.finish(curFamilyCellMap);</span>
+<span class="source-line-no">3703</span><span id="line-3703">          }</span>
+<span class="source-line-no">3704</span><span id="line-3704">        }</span>
+<span class="source-line-no">3705</span><span id="line-3705">        if (rowLock == null) {</span>
+<span class="source-line-no">3706</span><span id="line-3706">          // We failed to grab another lock</span>
+<span class="source-line-no">3707</span><span id="line-3707">          if (isAtomic()) {</span>
+<span class="source-line-no">3708</span><span id="line-3708">            region.storeHotnessProtector.finish(curFamilyCellMap);</span>
+<span class="source-line-no">3709</span><span id="line-3709">            throw new IOException("Can't apply all operations atomically!");</span>
+<span class="source-line-no">3710</span><span id="line-3710">          }</span>
+<span class="source-line-no">3711</span><span id="line-3711">          break; // Stop acquiring more rows for this batch</span>
+<span class="source-line-no">3712</span><span id="line-3712">        } else {</span>
+<span class="source-line-no">3713</span><span id="line-3713">          if (rowLock != prevRowLock) {</span>
+<span class="source-line-no">3714</span><span id="line-3714">            // It is a different row now, add this to the acquiredRowLocks and</span>
+<span class="source-line-no">3715</span><span id="line-3715">            // set prevRowLock to the new returned rowLock</span>
+<span class="source-line-no">3716</span><span id="line-3716">            acquiredRowLocks.add(rowLock);</span>
+<span class="source-line-no">3717</span><span id="line-3717">            prevRowLock = rowLock;</span>
+<span class="source-line-no">3718</span><span id="line-3718">          }</span>
+<span class="source-line-no">3719</span><span id="line-3719">        }</span>
+<span class="source-line-no">3720</span><span id="line-3720"></span>
+<span class="source-line-no">3721</span><span id="line-3721">        readyToWriteCount++;</span>
+<span class="source-line-no">3722</span><span id="line-3722">      }</span>
+<span class="source-line-no">3723</span><span id="line-3723">      return createMiniBatch(lastIndexExclusive, readyToWriteCount);</span>
+<span class="source-line-no">3724</span><span id="line-3724">    }</span>
+<span class="source-line-no">3725</span><span id="line-3725"></span>
+<span class="source-line-no">3726</span><span id="line-3726">    protected MiniBatchOperationInProgress&lt;Mutation&gt; createMiniBatch(final int lastIndexExclusive,</span>
+<span class="source-line-no">3727</span><span id="line-3727">      final int readyToWriteCount) {</span>
+<span class="source-line-no">3728</span><span id="line-3728">      return new MiniBatchOperationInProgress&lt;&gt;(getMutationsForCoprocs(), retCodeDetails,</span>
+<span class="source-line-no">3729</span><span id="line-3729">        walEditsFromCoprocessors, nextIndexToProcess, lastIndexExclusive, readyToWriteCount);</span>
+<span class="source-line-no">3730</span><span id="line-3730">    }</span>
+<span class="source-line-no">3731</span><span id="line-3731"></span>
+<span class="source-line-no">3732</span><span id="line-3732">    protected WALEdit createWALEdit(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {</span>
+<span class="source-line-no">3733</span><span id="line-3733">      return new WALEdit(miniBatchOp.getCellCount(), isInReplay());</span>
+<span class="source-line-no">3734</span><span id="line-3734">    }</span>
+<span class="source-line-no">3735</span><span id="line-3735"></span>
+<span class="source-line-no">3736</span><span id="line-3736">    /**</span>
+<span class="source-line-no">3737</span><span id="line-3737">     * Builds separate WALEdit per nonce by applying input mutations. If WALEdits from CP are</span>
+<span class="source-line-no">3738</span><span id="line-3738">     * present, they are merged to result WALEdit.</span>
+<span class="source-line-no">3739</span><span id="line-3739">     */</span>
+<span class="source-line-no">3740</span><span id="line-3740">    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt;</span>
+<span class="source-line-no">3741</span><span id="line-3741">      buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {</span>
+<span class="source-line-no">3742</span><span id="line-3742">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = new ArrayList&lt;&gt;();</span>
+<span class="source-line-no">3743</span><span id="line-3743"></span>
+<span class="source-line-no">3744</span><span id="line-3744">      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), new Visitor() {</span>
+<span class="source-line-no">3745</span><span id="line-3745">        private Pair&lt;NonceKey, WALEdit&gt; curWALEditForNonce;</span>
+<span class="source-line-no">3746</span><span id="line-3746"></span>
+<span class="source-line-no">3747</span><span id="line-3747">        @Override</span>
+<span class="source-line-no">3748</span><span id="line-3748">        public boolean visit(int index) throws IOException {</span>
+<span class="source-line-no">3749</span><span id="line-3749">          Mutation m = getMutation(index);</span>
+<span class="source-line-no">3750</span><span id="line-3750">          // we use durability of the original mutation for the mutation passed by CP.</span>
+<span class="source-line-no">3751</span><span id="line-3751">          if (region.getEffectiveDurability(m.getDurability()) == Durability.SKIP_WAL) {</span>
+<span class="source-line-no">3752</span><span id="line-3752">            region.recordMutationWithoutWal(m.getFamilyCellMap());</span>
+<span class="source-line-no">3753</span><span id="line-3753">            /**</span>
+<span class="source-line-no">3754</span><span id="line-3754">             * Here is for HBASE-26993,in order to make the new framework for region replication</span>
+<span class="source-line-no">3755</span><span id="line-3755">             * could work for SKIP_WAL, we save the {@link Mutation} which</span>
+<span class="source-line-no">3756</span><span id="line-3756">             * {@link Mutation#getDurability} is {@link Durability#SKIP_WAL} in miniBatchOp.</span>
+<span class="source-line-no">3757</span><span id="line-3757">             */</span>
+<span class="source-line-no">3758</span><span id="line-3758">            cacheSkipWALMutationForRegionReplication(miniBatchOp, walEdits, familyCellMaps[index]);</span>
+<span class="source-line-no">3759</span><span id="line-3759">            return true;</span>
+<span class="source-line-no">3760</span><span id="line-3760">          }</span>
+<span class="source-line-no">3761</span><span id="line-3761"></span>
+<span class="source-line-no">3762</span><span id="line-3762">          // the batch may contain multiple nonce keys (replay case). If so, write WALEdit for each.</span>
+<span class="source-line-no">3763</span><span id="line-3763">          // Given how nonce keys are originally written, these should be contiguous.</span>
+<span class="source-line-no">3764</span><span id="line-3764">          // They don't have to be, it will still work, just write more WALEdits than needed.</span>
+<span class="source-line-no">3765</span><span id="line-3765">          long nonceGroup = getNonceGroup(index);</span>
+<span class="source-line-no">3766</span><span id="line-3766">          long nonce = getNonce(index);</span>
+<span class="source-line-no">3767</span><span id="line-3767">          if (</span>
+<span class="source-line-no">3768</span><span id="line-3768">            curWALEditForNonce == null</span>
+<span class="source-line-no">3769</span><span id="line-3769">              || curWALEditForNonce.getFirst().getNonceGroup() != nonceGroup</span>
+<span class="source-line-no">3770</span><span id="line-3770">              || curWALEditForNonce.getFirst().getNonce() != nonce</span>
+<span class="source-line-no">3771</span><span id="line-3771">          ) {</span>
+<span class="source-line-no">3772</span><span id="line-3772">            curWALEditForNonce =</span>
+<span class="source-line-no">3773</span><span id="line-3773">              new Pair&lt;&gt;(new NonceKey(nonceGroup, nonce), createWALEdit(miniBatchOp));</span>
+<span class="source-line-no">3774</span><span id="line-3774">            walEdits.add(curWALEditForNonce);</span>
+<span class="source-line-no">3775</span><span id="line-3775">          }</span>
+<span class="source-line-no">3776</span><span id="line-3776">          WALEdit walEdit = curWALEditForNonce.getSecond();</span>
+<span class="source-line-no">3777</span><span id="line-3777"></span>
+<span class="source-line-no">3778</span><span id="line-3778">          // Add WAL edits from CPs.</span>
+<span class="source-line-no">3779</span><span id="line-3779">          WALEdit fromCP = walEditsFromCoprocessors[index];</span>
+<span class="source-line-no">3780</span><span id="line-3780">          List&lt;ExtendedCell&gt; cellsFromCP = fromCP == null</span>
+<span class="source-line-no">3781</span><span id="line-3781">            ? Collections.emptyList()</span>
+<span class="source-line-no">3782</span><span id="line-3782">            : WALEditInternalHelper.getExtendedCells(fromCP);</span>
+<span class="source-line-no">3783</span><span id="line-3783">          addNonSkipWALMutationsToWALEdit(miniBatchOp, walEdit, cellsFromCP, familyCellMaps[index]);</span>
+<span class="source-line-no">3784</span><span id="line-3784">          return true;</span>
+<span class="source-line-no">3785</span><span id="line-3785">        }</span>
+<span class="source-line-no">3786</span><span id="line-3786">      });</span>
+<span class="source-line-no">3787</span><span id="line-3787">      return walEdits;</span>
 <span class="source-line-no">3788</span><span id="line-3788">    }</span>
 <span class="source-line-no">3789</span><span id="line-3789"></span>
-<span class="source-line-no">3790</span><span id="line-3790">    /**</span>
-<span class="source-line-no">3791</span><span id="line-3791">     * Atomically apply the given map of family-&gt;edits to the memstore. This handles the consistency</span>
-<span class="source-line-no">3792</span><span id="line-3792">     * control on its own, but the caller should already have locked updatesLock.readLock(). This</span>
-<span class="source-line-no">3793</span><span id="line-3793">     * also does &lt;b&gt;not&lt;/b&gt; check the families for validity.</span>
-<span class="source-line-no">3794</span><span id="line-3794">     * @param familyMap Map of Cells by family</span>
-<span class="source-line-no">3795</span><span id="line-3795">     */</span>
-<span class="source-line-no">3796</span><span id="line-3796">    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyMap,</span>
-<span class="source-line-no">3797</span><span id="line-3797">      MemStoreSizing memstoreAccounting) {</span>
-<span class="source-line-no">3798</span><span id="line-3798">      for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; e : familyMap.entrySet()) {</span>
-<span class="source-line-no">3799</span><span id="line-3799">        byte[] family = e.getKey();</span>
-<span class="source-line-no">3800</span><span id="line-3800">        List&lt;ExtendedCell&gt; cells = e.getValue();</span>
-<span class="source-line-no">3801</span><span id="line-3801">        assert cells instanceof RandomAccess;</span>
-<span class="source-line-no">3802</span><span id="line-3802">        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);</span>
-<span class="source-line-no">3803</span><span id="line-3803">      }</span>
-<span class="source-line-no">3804</span><span id="line-3804">    }</span>
-<span class="source-line-no">3805</span><span id="line-3805">  }</span>
-<span class="source-line-no">3806</span><span id="line-3806"></span>
-<span class="source-line-no">3807</span><span id="line-3807">  /**</span>
-<span class="source-line-no">3808</span><span id="line-3808">   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most of</span>
-<span class="source-line-no">3809</span><span id="line-3809">   * the logic is same.</span>
-<span class="source-line-no">3810</span><span id="line-3810">   */</span>
-<span class="source-line-no">3811</span><span id="line-3811">  private static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {</span>
-<span class="source-line-no">3812</span><span id="line-3812"></span>
-<span class="source-line-no">3813</span><span id="line-3813">    // For nonce operations</span>
-<span class="source-line-no">3814</span><span id="line-3814">    private long nonceGroup;</span>
-<span class="source-line-no">3815</span><span id="line-3815">    private long nonce;</span>
-<span class="source-line-no">3816</span><span id="line-3816">    protected boolean canProceed;</span>
-<span class="source-line-no">3817</span><span id="line-3817">    private boolean regionReplicateEnable;</span>
-<span class="source-line-no">3818</span><span id="line-3818"></span>
-<span class="source-line-no">3819</span><span id="line-3819">    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,</span>
-<span class="source-line-no">3820</span><span id="line-3820">      long nonceGroup, long nonce) {</span>
-<span class="source-line-no">3821</span><span id="line-3821">      super(region, operations);</span>
-<span class="source-line-no">3822</span><span id="line-3822">      this.atomic = atomic;</span>
-<span class="source-line-no">3823</span><span id="line-3823">      this.nonceGroup = nonceGroup;</span>
-<span class="source-line-no">3824</span><span id="line-3824">      this.nonce = nonce;</span>
-<span class="source-line-no">3825</span><span id="line-3825">      this.regionReplicateEnable = region.regionReplicationSink.isPresent();</span>
-<span class="source-line-no">3826</span><span id="line-3826">    }</span>
-<span class="source-line-no">3827</span><span id="line-3827"></span>
-<span class="source-line-no">3828</span><span id="line-3828">    @Override</span>
-<span class="source-line-no">3829</span><span id="line-3829">    public Mutation getMutation(int index) {</span>
-<span class="source-line-no">3830</span><span id="line-3830">      return this.operations[index];</span>
-<span class="source-line-no">3831</span><span id="line-3831">    }</span>
-<span class="source-line-no">3832</span><span id="line-3832"></span>
-<span class="source-line-no">3833</span><span id="line-3833">    @Override</span>
-<span class="source-line-no">3834</span><span id="line-3834">    public long getNonceGroup(int index) {</span>
-<span class="source-line-no">3835</span><span id="line-3835">      return nonceGroup;</span>
-<span class="source-line-no">3836</span><span id="line-3836">    }</span>
+<span class="source-line-no">3790</span><span id="line-3790">    protected void addNonSkipWALMutationsToWALEdit(</span>
+<span class="source-line-no">3791</span><span id="line-3791">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, WALEdit walEdit,</span>
+<span class="source-line-no">3792</span><span id="line-3792">      List&lt;ExtendedCell&gt; cellsFromCP, Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
+<span class="source-line-no">3793</span><span id="line-3793">      doAddCellsToWALEdit(walEdit, cellsFromCP, familyCellMap);</span>
+<span class="source-line-no">3794</span><span id="line-3794">    }</span>
+<span class="source-line-no">3795</span><span id="line-3795"></span>
+<span class="source-line-no">3796</span><span id="line-3796">    protected static void doAddCellsToWALEdit(WALEdit walEdit, List&lt;ExtendedCell&gt; cellsFromCP,</span>
+<span class="source-line-no">3797</span><span id="line-3797">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
+<span class="source-line-no">3798</span><span id="line-3798">      WALEditInternalHelper.addExtendedCell(walEdit, cellsFromCP);</span>
+<span class="source-line-no">3799</span><span id="line-3799">      WALEditInternalHelper.addMap(walEdit, familyCellMap);</span>
+<span class="source-line-no">3800</span><span id="line-3800">    }</span>
+<span class="source-line-no">3801</span><span id="line-3801"></span>
+<span class="source-line-no">3802</span><span id="line-3802">    protected abstract void cacheSkipWALMutationForRegionReplication(</span>
+<span class="source-line-no">3803</span><span id="line-3803">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
+<span class="source-line-no">3804</span><span id="line-3804">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits, Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap);</span>
+<span class="source-line-no">3805</span><span id="line-3805"></span>
+<span class="source-line-no">3806</span><span id="line-3806">    /**</span>
+<span class="source-line-no">3807</span><span id="line-3807">     * This method completes mini-batch operations by calling postBatchMutate() CP hook (if</span>
+<span class="source-line-no">3808</span><span id="line-3808">     * required) and completing mvcc.</span>
+<span class="source-line-no">3809</span><span id="line-3809">     */</span>
+<span class="source-line-no">3810</span><span id="line-3810">    public void completeMiniBatchOperations(</span>
+<span class="source-line-no">3811</span><span id="line-3811">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)</span>
+<span class="source-line-no">3812</span><span id="line-3812">      throws IOException {</span>
+<span class="source-line-no">3813</span><span id="line-3813">      if (writeEntry != null) {</span>
+<span class="source-line-no">3814</span><span id="line-3814">        region.mvcc.completeAndWait(writeEntry);</span>
+<span class="source-line-no">3815</span><span id="line-3815">      }</span>
+<span class="source-line-no">3816</span><span id="line-3816">    }</span>
+<span class="source-line-no">3817</span><span id="line-3817"></span>
+<span class="source-line-no">3818</span><span id="line-3818">    public void doPostOpCleanupForMiniBatch(</span>
+<span class="source-line-no">3819</span><span id="line-3819">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WALEdit walEdit,</span>
+<span class="source-line-no">3820</span><span id="line-3820">      boolean success) throws IOException {</span>
+<span class="source-line-no">3821</span><span id="line-3821">      doFinishHotnessProtector(miniBatchOp);</span>
+<span class="source-line-no">3822</span><span id="line-3822">    }</span>
+<span class="source-line-no">3823</span><span id="line-3823"></span>
+<span class="source-line-no">3824</span><span id="line-3824">    private void</span>
+<span class="source-line-no">3825</span><span id="line-3825">      doFinishHotnessProtector(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) {</span>
+<span class="source-line-no">3826</span><span id="line-3826">      // check and return if the protector is not enabled</span>
+<span class="source-line-no">3827</span><span id="line-3827">      if (!region.storeHotnessProtector.isEnable()) {</span>
+<span class="source-line-no">3828</span><span id="line-3828">        return;</span>
+<span class="source-line-no">3829</span><span id="line-3829">      }</span>
+<span class="source-line-no">3830</span><span id="line-3830">      // miniBatchOp is null, if and only if lockRowsAndBuildMiniBatch throwing exception.</span>
+<span class="source-line-no">3831</span><span id="line-3831">      // This case was handled.</span>
+<span class="source-line-no">3832</span><span id="line-3832">      if (miniBatchOp == null) {</span>
+<span class="source-line-no">3833</span><span id="line-3833">        return;</span>
+<span class="source-line-no">3834</span><span id="line-3834">      }</span>
+<span class="source-line-no">3835</span><span id="line-3835"></span>
+<span class="source-line-no">3836</span><span id="line-3836">      final int finalLastIndexExclusive = miniBatchOp.getLastIndexExclusive();</span>
 <span class="source-line-no">3837</span><span id="line-3837"></span>
-<span class="source-line-no">3838</span><span id="line-3838">    @Override</span>
-<span class="source-line-no">3839</span><span id="line-3839">    public long getNonce(int index) {</span>
-<span class="source-line-no">3840</span><span id="line-3840">      return nonce;</span>
-<span class="source-line-no">3841</span><span id="line-3841">    }</span>
-<span class="source-line-no">3842</span><span id="line-3842"></span>
-<span class="source-line-no">3843</span><span id="line-3843">    @Override</span>
-<span class="source-line-no">3844</span><span id="line-3844">    public Mutation[] getMutationsForCoprocs() {</span>
-<span class="source-line-no">3845</span><span id="line-3845">      return this.operations;</span>
-<span class="source-line-no">3846</span><span id="line-3846">    }</span>
-<span class="source-line-no">3847</span><span id="line-3847"></span>
-<span class="source-line-no">3848</span><span id="line-3848">    @Override</span>
-<span class="source-line-no">3849</span><span id="line-3849">    public boolean isInReplay() {</span>
-<span class="source-line-no">3850</span><span id="line-3850">      return false;</span>
+<span class="source-line-no">3838</span><span id="line-3838">      for (int i = nextIndexToProcess; i &lt; finalLastIndexExclusive; i++) {</span>
+<span class="source-line-no">3839</span><span id="line-3839">        switch (retCodeDetails[i].getOperationStatusCode()) {</span>
+<span class="source-line-no">3840</span><span id="line-3840">          case SUCCESS:</span>
+<span class="source-line-no">3841</span><span id="line-3841">          case FAILURE:</span>
+<span class="source-line-no">3842</span><span id="line-3842">            region.storeHotnessProtector.finish(getMutation(i).getFamilyCellMap());</span>
+<span class="source-line-no">3843</span><span id="line-3843">            break;</span>
+<span class="source-line-no">3844</span><span id="line-3844">          default:</span>
+<span class="source-line-no">3845</span><span id="line-3845">            // do nothing</span>
+<span class="source-line-no">3846</span><span id="line-3846">            // We won't start the protector for NOT_RUN/BAD_FAMILY/SANITY_CHECK_FAILURE and the</span>
+<span class="source-line-no">3847</span><span id="line-3847">            // STORE_TOO_BUSY case is handled in StoreHotnessProtector#start</span>
+<span class="source-line-no">3848</span><span id="line-3848">            break;</span>
+<span class="source-line-no">3849</span><span id="line-3849">        }</span>
+<span class="source-line-no">3850</span><span id="line-3850">      }</span>
 <span class="source-line-no">3851</span><span id="line-3851">    }</span>
 <span class="source-line-no">3852</span><span id="line-3852"></span>
-<span class="source-line-no">3853</span><span id="line-3853">    @Override</span>
-<span class="source-line-no">3854</span><span id="line-3854">    public long getOrigLogSeqNum() {</span>
-<span class="source-line-no">3855</span><span id="line-3855">      return SequenceId.NO_SEQUENCE_ID;</span>
-<span class="source-line-no">3856</span><span id="line-3856">    }</span>
-<span class="source-line-no">3857</span><span id="line-3857"></span>
-<span class="source-line-no">3858</span><span id="line-3858">    @Override</span>
-<span class="source-line-no">3859</span><span id="line-3859">    public void startRegionOperation() throws IOException {</span>
-<span class="source-line-no">3860</span><span id="line-3860">      region.startRegionOperation(Operation.BATCH_MUTATE);</span>
-<span class="source-line-no">3861</span><span id="line-3861">    }</span>
-<span class="source-line-no">3862</span><span id="line-3862"></span>
-<span class="source-line-no">3863</span><span id="line-3863">    @Override</span>
-<span class="source-line-no">3864</span><span id="line-3864">    public void closeRegionOperation() throws IOException {</span>
-<span class="source-line-no">3865</span><span id="line-3865">      region.closeRegionOperation(Operation.BATCH_MUTATE);</span>
-<span class="source-line-no">3866</span><span id="line-3866">    }</span>
-<span class="source-line-no">3867</span><span id="line-3867"></span>
-<span class="source-line-no">3868</span><span id="line-3868">    @Override</span>
-<span class="source-line-no">3869</span><span id="line-3869">    public void checkAndPreparePut(Put p) throws IOException {</span>
-<span class="source-line-no">3870</span><span id="line-3870">      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());</span>
-<span class="source-line-no">3871</span><span id="line-3871">    }</span>
-<span class="source-line-no">3872</span><span id="line-3872"></span>
-<span class="source-line-no">3873</span><span id="line-3873">    @Override</span>
-<span class="source-line-no">3874</span><span id="line-3874">    public void checkAndPrepare() throws IOException {</span>
-<span class="source-line-no">3875</span><span id="line-3875">      // index 0: puts, index 1: deletes, index 2: increments, index 3: append</span>
-<span class="source-line-no">3876</span><span id="line-3876">      final int[] metrics = { 0, 0, 0, 0 };</span>
-<span class="source-line-no">3877</span><span id="line-3877"></span>
-<span class="source-line-no">3878</span><span id="line-3878">      visitBatchOperations(true, this.size(), new Visitor() {</span>
-<span class="source-line-no">3879</span><span id="line-3879">        private long now = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">3880</span><span id="line-3880">        private WALEdit walEdit;</span>
+<span class="source-line-no">3853</span><span id="line-3853">    /**</span>
+<span class="source-line-no">3854</span><span id="line-3854">     * Atomically apply the given map of family-&gt;edits to the memstore. This handles the consistency</span>
+<span class="source-line-no">3855</span><span id="line-3855">     * control on its own, but the caller should already have locked updatesLock.readLock(). This</span>
+<span class="source-line-no">3856</span><span id="line-3856">     * also does &lt;b&gt;not&lt;/b&gt; check the families for validity.</span>
+<span class="source-line-no">3857</span><span id="line-3857">     * @param familyMap Map of Cells by family</span>
+<span class="source-line-no">3858</span><span id="line-3858">     */</span>
+<span class="source-line-no">3859</span><span id="line-3859">    protected void applyFamilyMapToMemStore(Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyMap,</span>
+<span class="source-line-no">3860</span><span id="line-3860">      MemStoreSizing memstoreAccounting) {</span>
+<span class="source-line-no">3861</span><span id="line-3861">      for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; e : familyMap.entrySet()) {</span>
+<span class="source-line-no">3862</span><span id="line-3862">        byte[] family = e.getKey();</span>
+<span class="source-line-no">3863</span><span id="line-3863">        List&lt;ExtendedCell&gt; cells = e.getValue();</span>
+<span class="source-line-no">3864</span><span id="line-3864">        assert cells instanceof RandomAccess;</span>
+<span class="source-line-no">3865</span><span id="line-3865">        region.applyToMemStore(region.getStore(family), cells, false, memstoreAccounting);</span>
+<span class="source-line-no">3866</span><span id="line-3866">      }</span>
+<span class="source-line-no">3867</span><span id="line-3867">    }</span>
+<span class="source-line-no">3868</span><span id="line-3868">  }</span>
+<span class="source-line-no">3869</span><span id="line-3869"></span>
+<span class="source-line-no">3870</span><span id="line-3870">  /**</span>
+<span class="source-line-no">3871</span><span id="line-3871">   * Batch of mutation operations. Base class is shared with {@link ReplayBatchOperation} as most of</span>
+<span class="source-line-no">3872</span><span id="line-3872">   * the logic is same.</span>
+<span class="source-line-no">3873</span><span id="line-3873">   */</span>
+<span class="source-line-no">3874</span><span id="line-3874">  private static class MutationBatchOperation extends BatchOperation&lt;Mutation&gt; {</span>
+<span class="source-line-no">3875</span><span id="line-3875"></span>
+<span class="source-line-no">3876</span><span id="line-3876">    // For nonce operations</span>
+<span class="source-line-no">3877</span><span id="line-3877">    private long nonceGroup;</span>
+<span class="source-line-no">3878</span><span id="line-3878">    private long nonce;</span>
+<span class="source-line-no">3879</span><span id="line-3879">    protected boolean canProceed;</span>
+<span class="source-line-no">3880</span><span id="line-3880">    private boolean regionReplicateEnable;</span>
 <span class="source-line-no">3881</span><span id="line-3881"></span>
-<span class="source-line-no">3882</span><span id="line-3882">        @Override</span>
-<span class="source-line-no">3883</span><span id="line-3883">        public boolean visit(int index) throws IOException {</span>
-<span class="source-line-no">3884</span><span id="line-3884">          // Run coprocessor pre hook outside of locks to avoid deadlock</span>
-<span class="source-line-no">3885</span><span id="line-3885">          if (region.coprocessorHost != null) {</span>
-<span class="source-line-no">3886</span><span id="line-3886">            if (walEdit == null) {</span>
-<span class="source-line-no">3887</span><span id="line-3887">              walEdit = new WALEdit();</span>
-<span class="source-line-no">3888</span><span id="line-3888">            }</span>
-<span class="source-line-no">3889</span><span id="line-3889">            callPreMutateCPHook(index, walEdit, metrics);</span>
-<span class="source-line-no">3890</span><span id="line-3890">            if (!walEdit.isEmpty()) {</span>
-<span class="source-line-no">3891</span><span id="line-3891">              walEditsFromCoprocessors[index] = walEdit;</span>
-<span class="source-line-no">3892</span><span id="line-3892">              walEdit = null;</span>
-<span class="source-line-no">3893</span><span id="line-3893">            }</span>
-<span class="source-line-no">3894</span><span id="line-3894">          }</span>
-<span class="source-line-no">3895</span><span id="line-3895">          if (isOperationPending(index)) {</span>
-<span class="source-line-no">3896</span><span id="line-3896">            // TODO: Currently validation is done with current time before acquiring locks and</span>
-<span class="source-line-no">3897</span><span id="line-3897">            // updates are done with different timestamps after acquiring locks. This behavior is</span>
-<span class="source-line-no">3898</span><span id="line-3898">            // inherited from the code prior to this change. Can this be changed?</span>
-<span class="source-line-no">3899</span><span id="line-3899">            checkAndPrepareMutation(index, now);</span>
-<span class="source-line-no">3900</span><span id="line-3900">          }</span>
-<span class="source-line-no">3901</span><span id="line-3901">          return true;</span>
-<span class="source-line-no">3902</span><span id="line-3902">        }</span>
-<span class="source-line-no">3903</span><span id="line-3903">      });</span>
-<span class="source-line-no">3904</span><span id="line-3904"></span>
-<span class="source-line-no">3905</span><span id="line-3905">      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in</span>
-<span class="source-line-no">3906</span><span id="line-3906">      // normal processing.</span>
-<span class="source-line-no">3907</span><span id="line-3907">      // Update metrics in same way as it is done when we go the normal processing route (we now</span>
-<span class="source-line-no">3908</span><span id="line-3908">      // update general metrics though a Coprocessor did the work).</span>
-<span class="source-line-no">3909</span><span id="line-3909">      if (region.metricsRegion != null) {</span>
-<span class="source-line-no">3910</span><span id="line-3910">        if (metrics[0] &gt; 0) {</span>
-<span class="source-line-no">3911</span><span id="line-3911">          // There were some Puts in the batch.</span>
-<span class="source-line-no">3912</span><span id="line-3912">          region.metricsRegion.updatePut();</span>
-<span class="source-line-no">3913</span><span id="line-3913">        }</span>
-<span class="source-line-no">3914</span><span id="line-3914">        if (metrics[1] &gt; 0) {</span>
-<span class="source-line-no">3915</span><span id="line-3915">          // There were some Deletes in the batch.</span>
-<span class="source-line-no">3916</span><span id="line-3916">          region.metricsRegion.updateDelete();</span>
-<span class="source-line-no">3917</span><span id="line-3917">        }</span>
-<span class="source-line-no">3918</span><span id="line-3918">        if (metrics[2] &gt; 0) {</span>
-<span class="source-line-no">3919</span><span id="line-3919">          // There were some Increment in the batch.</span>
-<span class="source-line-no">3920</span><span id="line-3920">          region.metricsRegion.updateIncrement();</span>
-<span class="source-line-no">3921</span><span id="line-3921">        }</span>
-<span class="source-line-no">3922</span><span id="line-3922">        if (metrics[3] &gt; 0) {</span>
-<span class="source-line-no">3923</span><span id="line-3923">          // There were some Append in the batch.</span>
-<span class="source-line-no">3924</span><span id="line-3924">          region.metricsRegion.updateAppend();</span>
-<span class="source-line-no">3925</span><span id="line-3925">        }</span>
-<span class="source-line-no">3926</span><span id="line-3926">      }</span>
-<span class="source-line-no">3927</span><span id="line-3927">    }</span>
-<span class="source-line-no">3928</span><span id="line-3928"></span>
-<span class="source-line-no">3929</span><span id="line-3929">    @Override</span>
-<span class="source-line-no">3930</span><span id="line-3930">    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
-<span class="source-line-no">3931</span><span id="line-3931">      long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {</span>
-<span class="source-line-no">3932</span><span id="line-3932">      // For nonce operations</span>
-<span class="source-line-no">3933</span><span id="line-3933">      canProceed = startNonceOperation();</span>
-<span class="source-line-no">3934</span><span id="line-3934"></span>
-<span class="source-line-no">3935</span><span id="line-3935">      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {</span>
-<span class="source-line-no">3936</span><span id="line-3936">        Mutation mutation = getMutation(index);</span>
-<span class="source-line-no">3937</span><span id="line-3937">        if (mutation instanceof Put) {</span>
-<span class="source-line-no">3938</span><span id="line-3938">          HRegion.updateCellTimestamps(familyCellMaps[index].values(), Bytes.toBytes(timestamp));</span>
-<span class="source-line-no">3939</span><span id="line-3939">          miniBatchOp.incrementNumOfPuts();</span>
-<span class="source-line-no">3940</span><span id="line-3940">        } else if (mutation instanceof Delete) {</span>
-<span class="source-line-no">3941</span><span id="line-3941">          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], Bytes.toBytes(timestamp));</span>
-<span class="source-line-no">3942</span><span id="line-3942">          miniBatchOp.incrementNumOfDeletes();</span>
-<span class="source-line-no">3943</span><span id="line-3943">        } else if (mutation instanceof Increment || mutation instanceof Append) {</span>
-<span class="source-line-no">3944</span><span id="line-3944">          boolean returnResults;</span>
-<span class="source-line-no">3945</span><span id="line-3945">          if (mutation instanceof Increment) {</span>
-<span class="source-line-no">3946</span><span id="line-3946">            returnResults = ((Increment) mutation).isReturnResults();</span>
-<span class="source-line-no">3947</span><span id="line-3947">          } else {</span>
-<span class="source-line-no">3948</span><span id="line-3948">            returnResults = ((Append) mutation).isReturnResults();</span>
-<span class="source-line-no">3949</span><span id="line-3949">          }</span>
-<span class="source-line-no">3950</span><span id="line-3950"></span>
-<span class="source-line-no">3951</span><span id="line-3951">          // For nonce operations</span>
-<span class="source-line-no">3952</span><span id="line-3952">          if (!canProceed) {</span>
-<span class="source-line-no">3953</span><span id="line-3953">            Result result;</span>
-<span class="source-line-no">3954</span><span id="line-3954">            if (returnResults) {</span>
-<span class="source-line-no">3955</span><span id="line-3955">              // convert duplicate increment/append to get</span>
-<span class="source-line-no">3956</span><span id="line-3956">              List&lt;Cell&gt; results = region.get(toGet(mutation), false, nonceGroup, nonce);</span>
-<span class="source-line-no">3957</span><span id="line-3957">              result = Result.create(results);</span>
-<span class="source-line-no">3958</span><span id="line-3958">            } else {</span>
-<span class="source-line-no">3959</span><span id="line-3959">              result = Result.EMPTY_RESULT;</span>
-<span class="source-line-no">3960</span><span id="line-3960">            }</span>
-<span class="source-line-no">3961</span><span id="line-3961">            retCodeDetails[index] = new OperationStatus(OperationStatusCode.SUCCESS, result);</span>
-<span class="source-line-no">3962</span><span id="line-3962">            return true;</span>
+<span class="source-line-no">3882</span><span id="line-3882">    public MutationBatchOperation(final HRegion region, Mutation[] operations, boolean atomic,</span>
+<span class="source-line-no">3883</span><span id="line-3883">      long nonceGroup, long nonce) {</span>
+<span class="source-line-no">3884</span><span id="line-3884">      super(region, operations);</span>
+<span class="source-line-no">3885</span><span id="line-3885">      this.atomic = atomic;</span>
+<span class="source-line-no">3886</span><span id="line-3886">      this.nonceGroup = nonceGroup;</span>
+<span class="source-line-no">3887</span><span id="line-3887">      this.nonce = nonce;</span>
+<span class="source-line-no">3888</span><span id="line-3888">      this.regionReplicateEnable = region.regionReplicationSink.isPresent();</span>
+<span class="source-line-no">3889</span><span id="line-3889">    }</span>
+<span class="source-line-no">3890</span><span id="line-3890"></span>
+<span class="source-line-no">3891</span><span id="line-3891">    @Override</span>
+<span class="source-line-no">3892</span><span id="line-3892">    public Mutation getMutation(int index) {</span>
+<span class="source-line-no">3893</span><span id="line-3893">      return this.operations[index];</span>
+<span class="source-line-no">3894</span><span id="line-3894">    }</span>
+<span class="source-line-no">3895</span><span id="line-3895"></span>
+<span class="source-line-no">3896</span><span id="line-3896">    @Override</span>
+<span class="source-line-no">3897</span><span id="line-3897">    public long getNonceGroup(int index) {</span>
+<span class="source-line-no">3898</span><span id="line-3898">      return nonceGroup;</span>
+<span class="source-line-no">3899</span><span id="line-3899">    }</span>
+<span class="source-line-no">3900</span><span id="line-3900"></span>
+<span class="source-line-no">3901</span><span id="line-3901">    @Override</span>
+<span class="source-line-no">3902</span><span id="line-3902">    public long getNonce(int index) {</span>
+<span class="source-line-no">3903</span><span id="line-3903">      return nonce;</span>
+<span class="source-line-no">3904</span><span id="line-3904">    }</span>
+<span class="source-line-no">3905</span><span id="line-3905"></span>
+<span class="source-line-no">3906</span><span id="line-3906">    @Override</span>
+<span class="source-line-no">3907</span><span id="line-3907">    public Mutation[] getMutationsForCoprocs() {</span>
+<span class="source-line-no">3908</span><span id="line-3908">      return this.operations;</span>
+<span class="source-line-no">3909</span><span id="line-3909">    }</span>
+<span class="source-line-no">3910</span><span id="line-3910"></span>
+<span class="source-line-no">3911</span><span id="line-3911">    @Override</span>
+<span class="source-line-no">3912</span><span id="line-3912">    public boolean isInReplay() {</span>
+<span class="source-line-no">3913</span><span id="line-3913">      return false;</span>
+<span class="source-line-no">3914</span><span id="line-3914">    }</span>
+<span class="source-line-no">3915</span><span id="line-3915"></span>
+<span class="source-line-no">3916</span><span id="line-3916">    @Override</span>
+<span class="source-line-no">3917</span><span id="line-3917">    public long getOrigLogSeqNum() {</span>
+<span class="source-line-no">3918</span><span id="line-3918">      return SequenceId.NO_SEQUENCE_ID;</span>
+<span class="source-line-no">3919</span><span id="line-3919">    }</span>
+<span class="source-line-no">3920</span><span id="line-3920"></span>
+<span class="source-line-no">3921</span><span id="line-3921">    @Override</span>
+<span class="source-line-no">3922</span><span id="line-3922">    public void startRegionOperation() throws IOException {</span>
+<span class="source-line-no">3923</span><span id="line-3923">      region.startRegionOperation(Operation.BATCH_MUTATE);</span>
+<span class="source-line-no">3924</span><span id="line-3924">    }</span>
+<span class="source-line-no">3925</span><span id="line-3925"></span>
+<span class="source-line-no">3926</span><span id="line-3926">    @Override</span>
+<span class="source-line-no">3927</span><span id="line-3927">    public void closeRegionOperation() throws IOException {</span>
+<span class="source-line-no">3928</span><span id="line-3928">      region.closeRegionOperation(Operation.BATCH_MUTATE);</span>
+<span class="source-line-no">3929</span><span id="line-3929">    }</span>
+<span class="source-line-no">3930</span><span id="line-3930"></span>
+<span class="source-line-no">3931</span><span id="line-3931">    @Override</span>
+<span class="source-line-no">3932</span><span id="line-3932">    public void checkAndPreparePut(Put p) throws IOException {</span>
+<span class="source-line-no">3933</span><span id="line-3933">      region.checkFamilies(p.getFamilyCellMap().keySet(), p.getDurability());</span>
+<span class="source-line-no">3934</span><span id="line-3934">    }</span>
+<span class="source-line-no">3935</span><span id="line-3935"></span>
+<span class="source-line-no">3936</span><span id="line-3936">    @Override</span>
+<span class="source-line-no">3937</span><span id="line-3937">    public void checkAndPrepare() throws IOException {</span>
+<span class="source-line-no">3938</span><span id="line-3938">      // index 0: puts, index 1: deletes, index 2: increments, index 3: append</span>
+<span class="source-line-no">3939</span><span id="line-3939">      final int[] metrics = { 0, 0, 0, 0 };</span>
+<span class="source-line-no">3940</span><span id="line-3940"></span>
+<span class="source-line-no">3941</span><span id="line-3941">      visitBatchOperations(true, this.size(), new Visitor() {</span>
+<span class="source-line-no">3942</span><span id="line-3942">        private long now = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">3943</span><span id="line-3943">        private WALEdit walEdit;</span>
+<span class="source-line-no">3944</span><span id="line-3944"></span>
+<span class="source-line-no">3945</span><span id="line-3945">        @Override</span>
+<span class="source-line-no">3946</span><span id="line-3946">        public boolean visit(int index) throws IOException {</span>
+<span class="source-line-no">3947</span><span id="line-3947">          // Run coprocessor pre hook outside of locks to avoid deadlock</span>
+<span class="source-line-no">3948</span><span id="line-3948">          if (region.coprocessorHost != null) {</span>
+<span class="source-line-no">3949</span><span id="line-3949">            if (walEdit == null) {</span>
+<span class="source-line-no">3950</span><span id="line-3950">              walEdit = new WALEdit();</span>
+<span class="source-line-no">3951</span><span id="line-3951">            }</span>
+<span class="source-line-no">3952</span><span id="line-3952">            callPreMutateCPHook(index, walEdit, metrics);</span>
+<span class="source-line-no">3953</span><span id="line-3953">            if (!walEdit.isEmpty()) {</span>
+<span class="source-line-no">3954</span><span id="line-3954">              walEditsFromCoprocessors[index] = walEdit;</span>
+<span class="source-line-no">3955</span><span id="line-3955">              walEdit = null;</span>
+<span class="source-line-no">3956</span><span id="line-3956">            }</span>
+<span class="source-line-no">3957</span><span id="line-3957">          }</span>
+<span class="source-line-no">3958</span><span id="line-3958">          if (isOperationPending(index)) {</span>
+<span class="source-line-no">3959</span><span id="line-3959">            // TODO: Currently validation is done with current time before acquiring locks and</span>
+<span class="source-line-no">3960</span><span id="line-3960">            // updates are done with different timestamps after acquiring locks. This behavior is</span>
+<span class="source-line-no">3961</span><span id="line-3961">            // inherited from the code prior to this change. Can this be changed?</span>
+<span class="source-line-no">3962</span><span id="line-3962">            checkAndPrepareMutation(index, now);</span>
 <span class="source-line-no">3963</span><span id="line-3963">          }</span>
-<span class="source-line-no">3964</span><span id="line-3964"></span>
-<span class="source-line-no">3965</span><span id="line-3965">          Result result = null;</span>
-<span class="source-line-no">3966</span><span id="line-3966">          if (region.coprocessorHost != null) {</span>
-<span class="source-line-no">3967</span><span id="line-3967">            if (mutation instanceof Increment) {</span>
-<span class="source-line-no">3968</span><span id="line-3968">              result = region.coprocessorHost.preIncrementAfterRowLock((Increment) mutation);</span>
-<span class="source-line-no">3969</span><span id="line-3969">            } else {</span>
-<span class="source-line-no">3970</span><span id="line-3970">              result = region.coprocessorHost.preAppendAfterRowLock((Append) mutation);</span>
-<span class="source-line-no">3971</span><span id="line-3971">            }</span>
-<span class="source-line-no">3972</span><span id="line-3972">          }</span>
-<span class="source-line-no">3973</span><span id="line-3973">          if (result != null) {</span>
-<span class="source-line-no">3974</span><span id="line-3974">            retCodeDetails[index] = new OperationStatus(OperationStatusCode.SUCCESS,</span>
-<span class="source-line-no">3975</span><span id="line-3975">              returnResults ? result : Result.EMPTY_RESULT);</span>
-<span class="source-line-no">3976</span><span id="line-3976">            return true;</span>
-<span class="source-line-no">3977</span><span id="line-3977">          }</span>
-<span class="source-line-no">3978</span><span id="line-3978"></span>
-<span class="source-line-no">3979</span><span id="line-3979">          List&lt;ExtendedCell&gt; results = returnResults ? new ArrayList&lt;&gt;(mutation.size()) : null;</span>
-<span class="source-line-no">3980</span><span id="line-3980">          familyCellMaps[index] = reckonDeltas(mutation, results, timestamp);</span>
-<span class="source-line-no">3981</span><span id="line-3981">          this.results[index] = results != null ? Result.create(results) : Result.EMPTY_RESULT;</span>
-<span class="source-line-no">3982</span><span id="line-3982"></span>
-<span class="source-line-no">3983</span><span id="line-3983">          if (mutation instanceof Increment) {</span>
-<span class="source-line-no">3984</span><span id="line-3984">            miniBatchOp.incrementNumOfIncrements();</span>
-<span class="source-line-no">3985</span><span id="line-3985">          } else {</span>
-<span class="source-line-no">3986</span><span id="line-3986">            miniBatchOp.incrementNumOfAppends();</span>
-<span class="source-line-no">3987</span><span id="line-3987">          }</span>
+<span class="source-line-no">3964</span><span id="line-3964">          return true;</span>
+<span class="source-line-no">3965</span><span id="line-3965">        }</span>
+<span class="source-line-no">3966</span><span id="line-3966">      });</span>
+<span class="source-line-no">3967</span><span id="line-3967"></span>
+<span class="source-line-no">3968</span><span id="line-3968">      // FIXME: we may update metrics twice! here for all operations bypassed by CP and later in</span>
+<span class="source-line-no">3969</span><span id="line-3969">      // normal processing.</span>
+<span class="source-line-no">3970</span><span id="line-3970">      // Update metrics in same way as it is done when we go the normal processing route (we now</span>
+<span class="source-line-no">3971</span><span id="line-3971">      // update general metrics though a Coprocessor did the work).</span>
+<span class="source-line-no">3972</span><span id="line-3972">      if (region.metricsRegion != null) {</span>
+<span class="source-line-no">3973</span><span id="line-3973">        if (metrics[0] &gt; 0) {</span>
+<span class="source-line-no">3974</span><span id="line-3974">          // There were some Puts in the batch.</span>
+<span class="source-line-no">3975</span><span id="line-3975">          region.metricsRegion.updatePut();</span>
+<span class="source-line-no">3976</span><span id="line-3976">        }</span>
+<span class="source-line-no">3977</span><span id="line-3977">        if (metrics[1] &gt; 0) {</span>
+<span class="source-line-no">3978</span><span id="line-3978">          // There were some Deletes in the batch.</span>
+<span class="source-line-no">3979</span><span id="line-3979">          region.metricsRegion.updateDelete();</span>
+<span class="source-line-no">3980</span><span id="line-3980">        }</span>
+<span class="source-line-no">3981</span><span id="line-3981">        if (metrics[2] &gt; 0) {</span>
+<span class="source-line-no">3982</span><span id="line-3982">          // There were some Increment in the batch.</span>
+<span class="source-line-no">3983</span><span id="line-3983">          region.metricsRegion.updateIncrement();</span>
+<span class="source-line-no">3984</span><span id="line-3984">        }</span>
+<span class="source-line-no">3985</span><span id="line-3985">        if (metrics[3] &gt; 0) {</span>
+<span class="source-line-no">3986</span><span id="line-3986">          // There were some Append in the batch.</span>
+<span class="source-line-no">3987</span><span id="line-3987">          region.metricsRegion.updateAppend();</span>
 <span class="source-line-no">3988</span><span id="line-3988">        }</span>
-<span class="source-line-no">3989</span><span id="line-3989">        region.rewriteCellTags(familyCellMaps[index], mutation);</span>
-<span class="source-line-no">3990</span><span id="line-3990"></span>
-<span class="source-line-no">3991</span><span id="line-3991">        // update cell count</span>
-<span class="source-line-no">3992</span><span id="line-3992">        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {</span>
-<span class="source-line-no">3993</span><span id="line-3993">          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {</span>
-<span class="source-line-no">3994</span><span id="line-3994">            miniBatchOp.addCellCount(cells.size());</span>
-<span class="source-line-no">3995</span><span id="line-3995">          }</span>
-<span class="source-line-no">3996</span><span id="line-3996">        }</span>
+<span class="source-line-no">3989</span><span id="line-3989">      }</span>
+<span class="source-line-no">3990</span><span id="line-3990">    }</span>
+<span class="source-line-no">3991</span><span id="line-3991"></span>
+<span class="source-line-no">3992</span><span id="line-3992">    @Override</span>
+<span class="source-line-no">3993</span><span id="line-3993">    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
+<span class="source-line-no">3994</span><span id="line-3994">      long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {</span>
+<span class="source-line-no">3995</span><span id="line-3995">      // For nonce operations</span>
+<span class="source-line-no">3996</span><span id="line-3996">      canProceed = startNonceOperation();</span>
 <span class="source-line-no">3997</span><span id="line-3997"></span>
-<span class="source-line-no">3998</span><span id="line-3998">        WALEdit fromCP = walEditsFromCoprocessors[index];</span>
-<span class="source-line-no">3999</span><span id="line-3999">        if (fromCP != null) {</span>
-<span class="source-line-no">4000</span><span id="line-4000">          miniBatchOp.addCellCount(fromCP.size());</span>
-<span class="source-line-no">4001</span><span id="line-4001">        }</span>
-<span class="source-line-no">4002</span><span id="line-4002">        return true;</span>
-<span class="source-line-no">4003</span><span id="line-4003">      });</span>
-<span class="source-line-no">4004</span><span id="line-4004"></span>
-<span class="source-line-no">4005</span><span id="line-4005">      if (region.coprocessorHost != null) {</span>
-<span class="source-line-no">4006</span><span id="line-4006">        // calling the pre CP hook for batch mutation</span>
-<span class="source-line-no">4007</span><span id="line-4007">        region.coprocessorHost.preBatchMutate(miniBatchOp);</span>
-<span class="source-line-no">4008</span><span id="line-4008">        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);</span>
-<span class="source-line-no">4009</span><span id="line-4009">      }</span>
-<span class="source-line-no">4010</span><span id="line-4010">    }</span>
-<span class="source-line-no">4011</span><span id="line-4011"></span>
-<span class="source-line-no">4012</span><span id="line-4012">    /**</span>
-<span class="source-line-no">4013</span><span id="line-4013">     * Starts the nonce operation for a mutation, if needed.</span>
-<span class="source-line-no">4014</span><span id="line-4014">     * @return whether to proceed this mutation.</span>
-<span class="source-line-no">4015</span><span id="line-4015">     */</span>
-<span class="source-line-no">4016</span><span id="line-4016">    private boolean startNonceOperation() throws IOException {</span>
-<span class="source-line-no">4017</span><span id="line-4017">      if (</span>
-<span class="source-line-no">4018</span><span id="line-4018">        region.rsServices == null || region.rsServices.getNonceManager() == null</span>
-<span class="source-line-no">4019</span><span id="line-4019">          || nonce == HConstants.NO_NONCE</span>
-<span class="source-line-no">4020</span><span id="line-4020">      ) {</span>
-<span class="source-line-no">4021</span><span id="line-4021">        return true;</span>
-<span class="source-line-no">4022</span><span id="line-4022">      }</span>
-<span class="source-line-no">4023</span><span id="line-4023">      boolean canProceed;</span>
-<span class="source-line-no">4024</span><span id="line-4024">      try {</span>
-<span class="source-line-no">4025</span><span id="line-4025">        canProceed =</span>
-<span class="source-line-no">4026</span><span id="line-4026">          region.rsServices.getNonceManager().startOperation(nonceGroup, nonce, region.rsServices);</span>
-<span class="source-line-no">4027</span><span id="line-4027">      } catch (InterruptedException ex) {</span>
-<span class="source-line-no">4028</span><span id="line-4028">        throw new InterruptedIOException("Nonce start operation interrupted");</span>
-<span class="source-line-no">4029</span><span id="line-4029">      }</span>
-<span class="source-line-no">4030</span><span id="line-4030">      return canProceed;</span>
-<span class="source-line-no">4031</span><span id="line-4031">    }</span>
-<span class="source-line-no">4032</span><span id="line-4032"></span>
-<span class="source-line-no">4033</span><span id="line-4033">    /**</span>
-<span class="source-line-no">4034</span><span id="line-4034">     * Ends nonce operation for a mutation, if needed.</span>
-<span class="source-line-no">4035</span><span id="line-4035">     * @param success Whether the operation for this nonce has succeeded.</span>
-<span class="source-line-no">4036</span><span id="line-4036">     */</span>
-<span class="source-line-no">4037</span><span id="line-4037">    private void endNonceOperation(boolean success) {</span>
-<span class="source-line-no">4038</span><span id="line-4038">      if (</span>
-<span class="source-line-no">4039</span><span id="line-4039">        region.rsServices != null &amp;&amp; region.rsServices.getNonceManager() != null</span>
-<span class="source-line-no">4040</span><span id="line-4040">          &amp;&amp; nonce != HConstants.NO_NONCE</span>
-<span class="source-line-no">4041</span><span id="line-4041">      ) {</span>
-<span class="source-line-no">4042</span><span id="line-4042">        region.rsServices.getNonceManager().endOperation(nonceGroup, nonce, success);</span>
-<span class="source-line-no">4043</span><span id="line-4043">      }</span>
-<span class="source-line-no">4044</span><span id="line-4044">    }</span>
+<span class="source-line-no">3998</span><span id="line-3998">      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {</span>
+<span class="source-line-no">3999</span><span id="line-3999">        Mutation mutation = getMutation(index);</span>
+<span class="source-line-no">4000</span><span id="line-4000">        if (mutation instanceof Put) {</span>
+<span class="source-line-no">4001</span><span id="line-4001">          HRegion.updateCellTimestamps(familyCellMaps[index].values(), Bytes.toBytes(timestamp));</span>
+<span class="source-line-no">4002</span><span id="line-4002">          miniBatchOp.incrementNumOfPuts();</span>
+<span class="source-line-no">4003</span><span id="line-4003">        } else if (mutation instanceof Delete) {</span>
+<span class="source-line-no">4004</span><span id="line-4004">          region.prepareDeleteTimestamps(mutation, familyCellMaps[index], Bytes.toBytes(timestamp));</span>
+<span class="source-line-no">4005</span><span id="line-4005">          miniBatchOp.incrementNumOfDeletes();</span>
+<span class="source-line-no">4006</span><span id="line-4006">        } else if (mutation instanceof Increment || mutation instanceof Append) {</span>
+<span class="source-line-no">4007</span><span id="line-4007">          boolean returnResults;</span>
+<span class="source-line-no">4008</span><span id="line-4008">          if (mutation instanceof Increment) {</span>
+<span class="source-line-no">4009</span><span id="line-4009">            returnResults = ((Increment) mutation).isReturnResults();</span>
+<span class="source-line-no">4010</span><span id="line-4010">          } else {</span>
+<span class="source-line-no">4011</span><span id="line-4011">            returnResults = ((Append) mutation).isReturnResults();</span>
+<span class="source-line-no">4012</span><span id="line-4012">          }</span>
+<span class="source-line-no">4013</span><span id="line-4013"></span>
+<span class="source-line-no">4014</span><span id="line-4014">          // For nonce operations</span>
+<span class="source-line-no">4015</span><span id="line-4015">          if (!canProceed) {</span>
+<span class="source-line-no">4016</span><span id="line-4016">            Result result;</span>
+<span class="source-line-no">4017</span><span id="line-4017">            if (returnResults) {</span>
+<span class="source-line-no">4018</span><span id="line-4018">              // convert duplicate increment/append to get</span>
+<span class="source-line-no">4019</span><span id="line-4019">              List&lt;Cell&gt; results = region.get(toGet(mutation), false, nonceGroup, nonce);</span>
+<span class="source-line-no">4020</span><span id="line-4020">              result = Result.create(results);</span>
+<span class="source-line-no">4021</span><span id="line-4021">            } else {</span>
+<span class="source-line-no">4022</span><span id="line-4022">              result = Result.EMPTY_RESULT;</span>
+<span class="source-line-no">4023</span><span id="line-4023">            }</span>
+<span class="source-line-no">4024</span><span id="line-4024">            retCodeDetails[index] = new OperationStatus(OperationStatusCode.SUCCESS, result);</span>
+<span class="source-line-no">4025</span><span id="line-4025">            return true;</span>
+<span class="source-line-no">4026</span><span id="line-4026">          }</span>
+<span class="source-line-no">4027</span><span id="line-4027"></span>
+<span class="source-line-no">4028</span><span id="line-4028">          Result result = null;</span>
+<span class="source-line-no">4029</span><span id="line-4029">          if (region.coprocessorHost != null) {</span>
+<span class="source-line-no">4030</span><span id="line-4030">            if (mutation instanceof Increment) {</span>
+<span class="source-line-no">4031</span><span id="line-4031">              result = region.coprocessorHost.preIncrementAfterRowLock((Increment) mutation);</span>
+<span class="source-line-no">4032</span><span id="line-4032">            } else {</span>
+<span class="source-line-no">4033</span><span id="line-4033">              result = region.coprocessorHost.preAppendAfterRowLock((Append) mutation);</span>
+<span class="source-line-no">4034</span><span id="line-4034">            }</span>
+<span class="source-line-no">4035</span><span id="line-4035">          }</span>
+<span class="source-line-no">4036</span><span id="line-4036">          if (result != null) {</span>
+<span class="source-line-no">4037</span><span id="line-4037">            retCodeDetails[index] = new OperationStatus(OperationStatusCode.SUCCESS,</span>
+<span class="source-line-no">4038</span><span id="line-4038">              returnResults ? result : Result.EMPTY_RESULT);</span>
+<span class="source-line-no">4039</span><span id="line-4039">            return true;</span>
+<span class="source-line-no">4040</span><span id="line-4040">          }</span>
+<span class="source-line-no">4041</span><span id="line-4041"></span>
+<span class="source-line-no">4042</span><span id="line-4042">          List&lt;ExtendedCell&gt; results = returnResults ? new ArrayList&lt;&gt;(mutation.size()) : null;</span>
+<span class="source-line-no">4043</span><span id="line-4043">          familyCellMaps[index] = reckonDeltas(mutation, results, timestamp);</span>
+<span class="source-line-no">4044</span><span id="line-4044">          this.results[index] = results != null ? Result.create(results) : Result.EMPTY_RESULT;</span>
 <span class="source-line-no">4045</span><span id="line-4045"></span>
-<span class="source-line-no">4046</span><span id="line-4046">    private static Get toGet(final Mutation mutation) throws IOException {</span>
-<span class="source-line-no">4047</span><span id="line-4047">      assert mutation instanceof Increment || mutation instanceof Append;</span>
-<span class="source-line-no">4048</span><span id="line-4048">      Get get = new Get(mutation.getRow());</span>
-<span class="source-line-no">4049</span><span id="line-4049">      CellScanner cellScanner = mutation.cellScanner();</span>
-<span class="source-line-no">4050</span><span id="line-4050">      while (cellScanner.advance()) {</span>
-<span class="source-line-no">4051</span><span id="line-4051">        Cell cell = cellScanner.current();</span>
-<span class="source-line-no">4052</span><span id="line-4052">        get.addColumn(CellUtil.cloneFamily(cell), CellUtil.cloneQualifier(cell));</span>
-<span class="source-line-no">4053</span><span id="line-4053">      }</span>
-<span class="source-line-no">4054</span><span id="line-4054">      if (mutation instanceof Increment) {</span>
-<span class="source-line-no">4055</span><span id="line-4055">        // Increment</span>
-<span class="source-line-no">4056</span><span id="line-4056">        Increment increment = (Increment) mutation;</span>
-<span class="source-line-no">4057</span><span id="line-4057">        get.setTimeRange(increment.getTimeRange().getMin(), increment.getTimeRange().getMax());</span>
-<span class="source-line-no">4058</span><span id="line-4058">      } else {</span>
-<span class="source-line-no">4059</span><span id="line-4059">        // Append</span>
-<span class="source-line-no">4060</span><span id="line-4060">        Append append = (Append) mutation;</span>
-<span class="source-line-no">4061</span><span id="line-4061">        get.setTimeRange(append.getTimeRange().getMin(), append.getTimeRange().getMax());</span>
-<span class="source-line-no">4062</span><span id="line-4062">      }</span>
-<span class="source-line-no">4063</span><span id="line-4063">      for (Entry&lt;String, byte[]&gt; entry : mutation.getAttributesMap().entrySet()) {</span>
-<span class="source-line-no">4064</span><span id="line-4064">        get.setAttribute(entry.getKey(), entry.getValue());</span>
-<span class="source-line-no">4065</span><span id="line-4065">      }</span>
-<span class="source-line-no">4066</span><span id="line-4066">      return get;</span>
-<span class="source-line-no">4067</span><span id="line-4067">    }</span>
-<span class="source-line-no">4068</span><span id="line-4068"></span>
-<span class="source-line-no">4069</span><span id="line-4069">    private Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; reckonDeltas(Mutation mutation,</span>
-<span class="source-line-no">4070</span><span id="line-4070">      List&lt;ExtendedCell&gt; results, long now) throws IOException {</span>
-<span class="source-line-no">4071</span><span id="line-4071">      assert mutation instanceof Increment || mutation instanceof Append;</span>
-<span class="source-line-no">4072</span><span id="line-4072">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; ret = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
-<span class="source-line-no">4073</span><span id="line-4073">      // Process a Store/family at a time.</span>
-<span class="source-line-no">4074</span><span id="line-4074">      for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; entry : ClientInternalHelper</span>
-<span class="source-line-no">4075</span><span id="line-4075">        .getExtendedFamilyCellMap(mutation).entrySet()) {</span>
-<span class="source-line-no">4076</span><span id="line-4076">        final byte[] columnFamilyName = entry.getKey();</span>
-<span class="source-line-no">4077</span><span id="line-4077">        List&lt;ExtendedCell&gt; deltas = entry.getValue();</span>
-<span class="source-line-no">4078</span><span id="line-4078">        // Reckon for the Store what to apply to WAL and MemStore.</span>
-<span class="source-line-no">4079</span><span id="line-4079">        List&lt;ExtendedCell&gt; toApply =</span>
-<span class="source-line-no">4080</span><span id="line-4080">          reckonDeltasByStore(region.stores.get(columnFamilyName), mutation, now, deltas, results);</span>
-<span class="source-line-no">4081</span><span id="line-4081">        if (!toApply.isEmpty()) {</span>
-<span class="source-line-no">4082</span><span id="line-4082">          for (ExtendedCell cell : toApply) {</span>
-<span class="source-line-no">4083</span><span id="line-4083">            HStore store = region.getStore(cell);</span>
-<span class="source-line-no">4084</span><span id="line-4084">            if (store == null) {</span>
-<span class="source-line-no">4085</span><span id="line-4085">              region.checkFamily(CellUtil.cloneFamily(cell));</span>
-<span class="source-line-no">4086</span><span id="line-4086">            } else {</span>
-<span class="source-line-no">4087</span><span id="line-4087">              ret.computeIfAbsent(store.getColumnFamilyDescriptor().getName(),</span>
-<span class="source-line-no">4088</span><span id="line-4088">                key -&gt; new ArrayList&lt;&gt;()).add(cell);</span>
-<span class="source-line-no">4089</span><span id="line-4089">            }</span>
-<span class="source-line-no">4090</span><span id="line-4090">          }</span>
-<span class="source-line-no">4091</span><span id="line-4091">        }</span>
+<span class="source-line-no">4046</span><span id="line-4046">          if (mutation instanceof Increment) {</span>
+<span class="source-line-no">4047</span><span id="line-4047">            miniBatchOp.incrementNumOfIncrements();</span>
+<span class="source-line-no">4048</span><span id="line-4048">          } else {</span>
+<span class="source-line-no">4049</span><span id="line-4049">            miniBatchOp.incrementNumOfAppends();</span>
+<span class="source-line-no">4050</span><span id="line-4050">          }</span>
+<span class="source-line-no">4051</span><span id="line-4051">        }</span>
+<span class="source-line-no">4052</span><span id="line-4052">        region.rewriteCellTags(familyCellMaps[index], mutation);</span>
+<span class="source-line-no">4053</span><span id="line-4053"></span>
+<span class="source-line-no">4054</span><span id="line-4054">        // update cell count</span>
+<span class="source-line-no">4055</span><span id="line-4055">        if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {</span>
+<span class="source-line-no">4056</span><span id="line-4056">          for (List&lt;Cell&gt; cells : mutation.getFamilyCellMap().values()) {</span>
+<span class="source-line-no">4057</span><span id="line-4057">            miniBatchOp.addCellCount(cells.size());</span>
+<span class="source-line-no">4058</span><span id="line-4058">          }</span>
+<span class="source-line-no">4059</span><span id="line-4059">        }</span>
+<span class="source-line-no">4060</span><span id="line-4060"></span>
+<span class="source-line-no">4061</span><span id="line-4061">        WALEdit fromCP = walEditsFromCoprocessors[index];</span>
+<span class="source-line-no">4062</span><span id="line-4062">        if (fromCP != null) {</span>
+<span class="source-line-no">4063</span><span id="line-4063">          miniBatchOp.addCellCount(fromCP.size());</span>
+<span class="source-line-no">4064</span><span id="line-4064">        }</span>
+<span class="source-line-no">4065</span><span id="line-4065">        return true;</span>
+<span class="source-line-no">4066</span><span id="line-4066">      });</span>
+<span class="source-line-no">4067</span><span id="line-4067"></span>
+<span class="source-line-no">4068</span><span id="line-4068">      if (region.coprocessorHost != null) {</span>
+<span class="source-line-no">4069</span><span id="line-4069">        // calling the pre CP hook for batch mutation</span>
+<span class="source-line-no">4070</span><span id="line-4070">        region.coprocessorHost.preBatchMutate(miniBatchOp);</span>
+<span class="source-line-no">4071</span><span id="line-4071">        checkAndMergeCPMutations(miniBatchOp, acquiredRowLocks, timestamp);</span>
+<span class="source-line-no">4072</span><span id="line-4072">      }</span>
+<span class="source-line-no">4073</span><span id="line-4073">    }</span>
+<span class="source-line-no">4074</span><span id="line-4074"></span>
+<span class="source-line-no">4075</span><span id="line-4075">    /**</span>
+<span class="source-line-no">4076</span><span id="line-4076">     * Starts the nonce operation for a mutation, if needed.</span>
+<span class="source-line-no">4077</span><span id="line-4077">     * @return whether to proceed this mutation.</span>
+<span class="source-line-no">4078</span><span id="line-4078">     */</span>
+<span class="source-line-no">4079</span><span id="line-4079">    private boolean startNonceOperation() throws IOException {</span>
+<span class="source-line-no">4080</span><span id="line-4080">      if (</span>
+<span class="source-line-no">4081</span><span id="line-4081">        region.rsServices == null || region.rsServices.getNonceManager() == null</span>
+<span class="source-line-no">4082</span><span id="line-4082">          || nonce == HConstants.NO_NONCE</span>
+<span class="source-line-no">4083</span><span id="line-4083">      ) {</span>
+<span class="source-line-no">4084</span><span id="line-4084">        return true;</span>
+<span class="source-line-no">4085</span><span id="line-4085">      }</span>
+<span class="source-line-no">4086</span><span id="line-4086">      boolean canProceed;</span>
+<span class="source-line-no">4087</span><span id="line-4087">      try {</span>
+<span class="source-line-no">4088</span><span id="line-4088">        canProceed =</span>
+<span class="source-line-no">4089</span><span id="line-4089">          region.rsServices.getNonceManager().startOperation(nonceGroup, nonce, region.rsServices);</span>
+<span class="source-line-no">4090</span><span id="line-4090">      } catch (InterruptedException ex) {</span>
+<span class="source-line-no">4091</span><span id="line-4091">        throw new InterruptedIOException("Nonce start operation interrupted");</span>
 <span class="source-line-no">4092</span><span id="line-4092">      }</span>
-<span class="source-line-no">4093</span><span id="line-4093">      return ret;</span>
+<span class="source-line-no">4093</span><span id="line-4093">      return canProceed;</span>
 <span class="source-line-no">4094</span><span id="line-4094">    }</span>
 <span class="source-line-no">4095</span><span id="line-4095"></span>
 <span class="source-line-no">4096</span><span id="line-4096">    /**</span>
-<span class="source-line-no">4097</span><span id="line-4097">     * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed column</span>
-<span class="source-line-no">4098</span><span id="line-4098">     * family/Store. Does Get of current value and then adds passed in deltas for this Store</span>
-<span class="source-line-no">4099</span><span id="line-4099">     * returning the result.</span>
-<span class="source-line-no">4100</span><span id="line-4100">     * @param mutation The encompassing Mutation object</span>
-<span class="source-line-no">4101</span><span id="line-4101">     * @param deltas   Changes to apply to this Store; either increment amount or data to append</span>
-<span class="source-line-no">4102</span><span id="line-4102">     * @param results  In here we accumulate all the Cells we are to return to the client. If null,</span>
-<span class="source-line-no">4103</span><span id="line-4103">     *                 client doesn't want results returned.</span>
-<span class="source-line-no">4104</span><span id="line-4104">     * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current values. Side</span>
-<span class="source-line-no">4105</span><span id="line-4105">     *         effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.</span>
-<span class="source-line-no">4106</span><span id="line-4106">     */</span>
-<span class="source-line-no">4107</span><span id="line-4107">    private List&lt;ExtendedCell&gt; reckonDeltasByStore(HStore store, Mutation mutation, long now,</span>
-<span class="source-line-no">4108</span><span id="line-4108">      List&lt;ExtendedCell&gt; deltas, List&lt;ExtendedCell&gt; results) throws IOException {</span>
-<span class="source-line-no">4109</span><span id="line-4109">      assert mutation instanceof Increment || mutation instanceof Append;</span>
-<span class="source-line-no">4110</span><span id="line-4110">      byte[] columnFamily = store.getColumnFamilyDescriptor().getName();</span>
-<span class="source-line-no">4111</span><span id="line-4111">      List&lt;Pair&lt;ExtendedCell, ExtendedCell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());</span>
-<span class="source-line-no">4112</span><span id="line-4112"></span>
-<span class="source-line-no">4113</span><span id="line-4113">      // Sort the cells so that they match the order that they appear in the Get results.</span>
-<span class="source-line-no">4114</span><span id="line-4114">      // Otherwise, we won't be able to find the existing values if the cells are not specified</span>
-<span class="source-line-no">4115</span><span id="line-4115">      // in order by the client since cells are in an array list.</span>
-<span class="source-line-no">4116</span><span id="line-4116">      deltas.sort(store.getComparator());</span>
-<span class="source-line-no">4117</span><span id="line-4117"></span>
-<span class="source-line-no">4118</span><span id="line-4118">      // Get previous values for all columns in this family.</span>
-<span class="source-line-no">4119</span><span id="line-4119">      Get get = new Get(mutation.getRow());</span>
-<span class="source-line-no">4120</span><span id="line-4120">      for (ExtendedCell cell : deltas) {</span>
-<span class="source-line-no">4121</span><span id="line-4121">        get.addColumn(columnFamily, CellUtil.cloneQualifier(cell));</span>
-<span class="source-line-no">4122</span><span id="line-4122">      }</span>
-<span class="source-line-no">4123</span><span id="line-4123">      TimeRange tr;</span>
-<span class="source-line-no">4124</span><span id="line-4124">      if (mutation instanceof Increment) {</span>
-<span class="source-line-no">4125</span><span id="line-4125">        tr = ((Increment) mutation).getTimeRange();</span>
-<span class="source-line-no">4126</span><span id="line-4126">      } else {</span>
-<span class="source-line-no">4127</span><span id="line-4127">        tr = ((Append) mutation).getTimeRange();</span>
+<span class="source-line-no">4097</span><span id="line-4097">     * Ends nonce operation for a mutation, if needed.</span>
+<span class="source-line-no">4098</span><span id="line-4098">     * @param success Whether the operation for this nonce has succeeded.</span>
+<span class="source-line-no">4099</span><span id="line-4099">     */</span>
+<span class="source-line-no">4100</span><span id="line-4100">    private void endNonceOperation(boolean success) {</span>
+<span class="source-line-no">4101</span><span id="line-4101">      if (</span>
+<span class="source-line-no">4102</span><span id="line-4102">        region.rsServices != null &amp;&amp; region.rsServices.getNonceManager() != null</span>
+<span class="source-line-no">4103</span><span id="line-4103">          &amp;&amp; nonce != HConstants.NO_NONCE</span>
+<span class="source-line-no">4104</span><span id="line-4104">      ) {</span>
+<span class="source-line-no">4105</span><span id="line-4105">        region.rsServices.getNonceManager().endOperation(nonceGroup, nonce, success);</span>
+<span class="source-line-no">4106</span><span id="line-4106">      }</span>
+<span class="source-line-no">4107</span><span id="line-4107">    }</span>
+<span class="source-line-no">4108</span><span id="line-4108"></span>
+<span class="source-line-no">4109</span><span id="line-4109">    private static Get toGet(final Mutation mutation) throws IOException {</span>
+<span class="source-line-no">4110</span><span id="line-4110">      assert mutation instanceof Increment || mutation instanceof Append;</span>
+<span class="source-line-no">4111</span><span id="line-4111">      Get get = new Get(mutation.getRow());</span>
+<span class="source-line-no">4112</span><span id="line-4112">      CellScanner cellScanner = mutation.cellScanner();</span>
+<span class="source-line-no">4113</span><span id="line-4113">      while (cellScanner.advance()) {</span>
+<span class="source-line-no">4114</span><span id="line-4114">        Cell cell = cellScanner.current();</span>
+<span class="source-line-no">4115</span><span id="line-4115">        get.addColumn(CellUtil.cloneFamily(cell), CellUtil.cloneQualifier(cell));</span>
+<span class="source-line-no">4116</span><span id="line-4116">      }</span>
+<span class="source-line-no">4117</span><span id="line-4117">      if (mutation instanceof Increment) {</span>
+<span class="source-line-no">4118</span><span id="line-4118">        // Increment</span>
+<span class="source-line-no">4119</span><span id="line-4119">        Increment increment = (Increment) mutation;</span>
+<span class="source-line-no">4120</span><span id="line-4120">        get.setTimeRange(increment.getTimeRange().getMin(), increment.getTimeRange().getMax());</span>
+<span class="source-line-no">4121</span><span id="line-4121">      } else {</span>
+<span class="source-line-no">4122</span><span id="line-4122">        // Append</span>
+<span class="source-line-no">4123</span><span id="line-4123">        Append append = (Append) mutation;</span>
+<span class="source-line-no">4124</span><span id="line-4124">        get.setTimeRange(append.getTimeRange().getMin(), append.getTimeRange().getMax());</span>
+<span class="source-line-no">4125</span><span id="line-4125">      }</span>
+<span class="source-line-no">4126</span><span id="line-4126">      for (Entry&lt;String, byte[]&gt; entry : mutation.getAttributesMap().entrySet()) {</span>
+<span class="source-line-no">4127</span><span id="line-4127">        get.setAttribute(entry.getKey(), entry.getValue());</span>
 <span class="source-line-no">4128</span><span id="line-4128">      }</span>
-<span class="source-line-no">4129</span><span id="line-4129"></span>
-<span class="source-line-no">4130</span><span id="line-4130">      if (tr != null) {</span>
-<span class="source-line-no">4131</span><span id="line-4131">        get.setTimeRange(tr.getMin(), tr.getMax());</span>
-<span class="source-line-no">4132</span><span id="line-4132">      }</span>
-<span class="source-line-no">4133</span><span id="line-4133"></span>
-<span class="source-line-no">4134</span><span id="line-4134">      try (RegionScanner scanner = region.getScanner(new Scan(get))) {</span>
-<span class="source-line-no">4135</span><span id="line-4135">        // NOTE: Please don't use HRegion.get() instead,</span>
-<span class="source-line-no">4136</span><span id="line-4136">        // because it will copy cells to heap. See HBASE-26036</span>
-<span class="source-line-no">4137</span><span id="line-4137">        List&lt;ExtendedCell&gt; currentValues = new ArrayList&lt;&gt;();</span>
-<span class="source-line-no">4138</span><span id="line-4138">        scanner.next(currentValues);</span>
-<span class="source-line-no">4139</span><span id="line-4139">        // Iterate the input columns and update existing values if they were found, otherwise</span>
-<span class="source-line-no">4140</span><span id="line-4140">        // add new column initialized to the delta amount</span>
-<span class="source-line-no">4141</span><span id="line-4141">        int currentValuesIndex = 0;</span>
-<span class="source-line-no">4142</span><span id="line-4142">        for (int i = 0; i &lt; deltas.size(); i++) {</span>
-<span class="source-line-no">4143</span><span id="line-4143">          ExtendedCell delta = deltas.get(i);</span>
-<span class="source-line-no">4144</span><span id="line-4144">          ExtendedCell currentValue = null;</span>
-<span class="source-line-no">4145</span><span id="line-4145">          if (</span>
-<span class="source-line-no">4146</span><span id="line-4146">            currentValuesIndex &lt; currentValues.size()</span>
-<span class="source-line-no">4147</span><span id="line-4147">              &amp;&amp; CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)</span>
-<span class="source-line-no">4148</span><span id="line-4148">          ) {</span>
-<span class="source-line-no">4149</span><span id="line-4149">            currentValue = currentValues.get(currentValuesIndex);</span>
-<span class="source-line-no">4150</span><span id="line-4150">            if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {</span>
-<span class="source-line-no">4151</span><span id="line-4151">              currentValuesIndex++;</span>
+<span class="source-line-no">4129</span><span id="line-4129">      return get;</span>
+<span class="source-line-no">4130</span><span id="line-4130">    }</span>
+<span class="source-line-no">4131</span><span id="line-4131"></span>
+<span class="source-line-no">4132</span><span id="line-4132">    private Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; reckonDeltas(Mutation mutation,</span>
+<span class="source-line-no">4133</span><span id="line-4133">      List&lt;ExtendedCell&gt; results, long now) throws IOException {</span>
+<span class="source-line-no">4134</span><span id="line-4134">      assert mutation instanceof Increment || mutation instanceof Append;</span>
+<span class="source-line-no">4135</span><span id="line-4135">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; ret = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
+<span class="source-line-no">4136</span><span id="line-4136">      // Process a Store/family at a time.</span>
+<span class="source-line-no">4137</span><span id="line-4137">      for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; entry : ClientInternalHelper</span>
+<span class="source-line-no">4138</span><span id="line-4138">        .getExtendedFamilyCellMap(mutation).entrySet()) {</span>
+<span class="source-line-no">4139</span><span id="line-4139">        final byte[] columnFamilyName = entry.getKey();</span>
+<span class="source-line-no">4140</span><span id="line-4140">        List&lt;ExtendedCell&gt; deltas = entry.getValue();</span>
+<span class="source-line-no">4141</span><span id="line-4141">        // Reckon for the Store what to apply to WAL and MemStore.</span>
+<span class="source-line-no">4142</span><span id="line-4142">        List&lt;ExtendedCell&gt; toApply =</span>
+<span class="source-line-no">4143</span><span id="line-4143">          reckonDeltasByStore(region.stores.get(columnFamilyName), mutation, now, deltas, results);</span>
+<span class="source-line-no">4144</span><span id="line-4144">        if (!toApply.isEmpty()) {</span>
+<span class="source-line-no">4145</span><span id="line-4145">          for (ExtendedCell cell : toApply) {</span>
+<span class="source-line-no">4146</span><span id="line-4146">            HStore store = region.getStore(cell);</span>
+<span class="source-line-no">4147</span><span id="line-4147">            if (store == null) {</span>
+<span class="source-line-no">4148</span><span id="line-4148">              region.checkFamily(CellUtil.cloneFamily(cell));</span>
+<span class="source-line-no">4149</span><span id="line-4149">            } else {</span>
+<span class="source-line-no">4150</span><span id="line-4150">              ret.computeIfAbsent(store.getColumnFamilyDescriptor().getName(),</span>
+<span class="source-line-no">4151</span><span id="line-4151">                key -&gt; new ArrayList&lt;&gt;()).add(cell);</span>
 <span class="source-line-no">4152</span><span id="line-4152">            }</span>
 <span class="source-line-no">4153</span><span id="line-4153">          }</span>
-<span class="source-line-no">4154</span><span id="line-4154">          // Switch on whether this an increment or an append building the new Cell to apply.</span>
-<span class="source-line-no">4155</span><span id="line-4155">          ExtendedCell newCell;</span>
-<span class="source-line-no">4156</span><span id="line-4156">          if (mutation instanceof Increment) {</span>
-<span class="source-line-no">4157</span><span id="line-4157">            long deltaAmount = getLongValue(delta);</span>
-<span class="source-line-no">4158</span><span id="line-4158">            final long newValue =</span>
-<span class="source-line-no">4159</span><span id="line-4159">              currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;</span>
-<span class="source-line-no">4160</span><span id="line-4160">            newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation,</span>
-<span class="source-line-no">4161</span><span id="line-4161">              (oldCell) -&gt; Bytes.toBytes(newValue));</span>
-<span class="source-line-no">4162</span><span id="line-4162">          } else {</span>
-<span class="source-line-no">4163</span><span id="line-4163">            newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation,</span>
-<span class="source-line-no">4164</span><span id="line-4164">              (oldCell) -&gt; ByteBuffer</span>
-<span class="source-line-no">4165</span><span id="line-4165">                .wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])</span>
-<span class="source-line-no">4166</span><span id="line-4166">                .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())</span>
-<span class="source-line-no">4167</span><span id="line-4167">                .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())</span>
-<span class="source-line-no">4168</span><span id="line-4168">                .array());</span>
-<span class="source-line-no">4169</span><span id="line-4169">          }</span>
-<span class="source-line-no">4170</span><span id="line-4170">          if (region.maxCellSize &gt; 0) {</span>
-<span class="source-line-no">4171</span><span id="line-4171">            int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);</span>
-<span class="source-line-no">4172</span><span id="line-4172">            if (newCellSize &gt; region.maxCellSize) {</span>
-<span class="source-line-no">4173</span><span id="line-4173">              String msg = "Cell with size " + newCellSize + " exceeds limit of "</span>
-<span class="source-line-no">4174</span><span id="line-4174">                + region.maxCellSize + " bytes in region " + this;</span>
-<span class="source-line-no">4175</span><span id="line-4175">              LOG.debug(msg);</span>
-<span class="source-line-no">4176</span><span id="line-4176">              throw new DoNotRetryIOException(msg);</span>
-<span class="source-line-no">4177</span><span id="line-4177">            }</span>
-<span class="source-line-no">4178</span><span id="line-4178">          }</span>
-<span class="source-line-no">4179</span><span id="line-4179">          cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));</span>
-<span class="source-line-no">4180</span><span id="line-4180">          // Add to results to get returned to the Client. If null, cilent does not want results.</span>
-<span class="source-line-no">4181</span><span id="line-4181">          if (results != null) {</span>
-<span class="source-line-no">4182</span><span id="line-4182">            results.add(newCell);</span>
-<span class="source-line-no">4183</span><span id="line-4183">          }</span>
-<span class="source-line-no">4184</span><span id="line-4184">        }</span>
-<span class="source-line-no">4185</span><span id="line-4185">        // Give coprocessors a chance to update the new cells before apply to WAL or memstore</span>
-<span class="source-line-no">4186</span><span id="line-4186">        if (region.coprocessorHost != null) {</span>
-<span class="source-line-no">4187</span><span id="line-4187">          // Here the operation must be increment or append.</span>
-<span class="source-line-no">4188</span><span id="line-4188">          cellPairs = mutation instanceof Increment</span>
-<span class="source-line-no">4189</span><span id="line-4189">            ? region.coprocessorHost.postIncrementBeforeWAL(mutation, (List) cellPairs)</span>
-<span class="source-line-no">4190</span><span id="line-4190">            : region.coprocessorHost.postAppendBeforeWAL(mutation, (List) cellPairs);</span>
-<span class="source-line-no">4191</span><span id="line-4191">        }</span>
-<span class="source-line-no">4192</span><span id="line-4192">      }</span>
-<span class="source-line-no">4193</span><span id="line-4193">      return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());</span>
-<span class="source-line-no">4194</span><span id="line-4194">    }</span>
-<span class="source-line-no">4195</span><span id="line-4195"></span>
-<span class="source-line-no">4196</span><span id="line-4196">    private static ExtendedCell reckonDelta(final ExtendedCell delta,</span>
-<span class="source-line-no">4197</span><span id="line-4197">      final ExtendedCell currentCell, final byte[] columnFamily, final long now, Mutation mutation,</span>
-<span class="source-line-no">4198</span><span id="line-4198">      Function&lt;ExtendedCell, byte[]&gt; supplier) throws IOException {</span>
-<span class="source-line-no">4199</span><span id="line-4199">      // Forward any tags found on the delta.</span>
-<span class="source-line-no">4200</span><span id="line-4200">      List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);</span>
-<span class="source-line-no">4201</span><span id="line-4201">      if (currentCell != null) {</span>
-<span class="source-line-no">4202</span><span id="line-4202">        tags = TagUtil.carryForwardTags(tags, currentCell);</span>
-<span class="source-line-no">4203</span><span id="line-4203">        tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());</span>
-<span class="source-line-no">4204</span><span id="line-4204">        byte[] newValue = supplier.apply(currentCell);</span>
-<span class="source-line-no">4205</span><span id="line-4205">        return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)</span>
-<span class="source-line-no">4206</span><span id="line-4206">          .setRow(mutation.getRow(), 0, mutation.getRow().length)</span>
-<span class="source-line-no">4207</span><span id="line-4207">          .setFamily(columnFamily, 0, columnFamily.length)</span>
-<span class="source-line-no">4208</span><span id="line-4208">          // copy the qualifier if the cell is located in shared memory.</span>
-<span class="source-line-no">4209</span><span id="line-4209">          .setQualifier(CellUtil.cloneQualifier(delta))</span>
-<span class="source-line-no">4210</span><span id="line-4210">          .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))</span>
-<span class="source-line-no">4211</span><span id="line-4211">          .setType(KeyValue.Type.Put.getCode()).setValue(newValue, 0, newValue.length)</span>
-<span class="source-line-no">4212</span><span id="line-4212">          .setTags(TagUtil.fromList(tags)).build();</span>
-<span class="source-line-no">4213</span><span id="line-4213">      } else {</span>
-<span class="source-line-no">4214</span><span id="line-4214">        tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());</span>
-<span class="source-line-no">4215</span><span id="line-4215">        PrivateCellUtil.updateLatestStamp(delta, now);</span>
-<span class="source-line-no">4216</span><span id="line-4216">        ExtendedCell deltaCell = (ExtendedCell) delta;</span>
-<span class="source-line-no">4217</span><span id="line-4217">        return CollectionUtils.isEmpty(tags)</span>
-<span class="source-line-no">4218</span><span id="line-4218">          ? deltaCell</span>
-<span class="source-line-no">4219</span><span id="line-4219">          : PrivateCellUtil.createCell(deltaCell, tags);</span>
-<span class="source-line-no">4220</span><span id="line-4220">      }</span>
-<span class="source-line-no">4221</span><span id="line-4221">    }</span>
-<span class="source-line-no">4222</span><span id="line-4222"></span>
-<span class="source-line-no">4223</span><span id="line-4223">    /** Returns Get the long out of the passed in Cell */</span>
-<span class="source-line-no">4224</span><span id="line-4224">    private static long getLongValue(final Cell cell) throws DoNotRetryIOException {</span>
-<span class="source-line-no">4225</span><span id="line-4225">      int len = cell.getValueLength();</span>
-<span class="source-line-no">4226</span><span id="line-4226">      if (len != Bytes.SIZEOF_LONG) {</span>
-<span class="source-line-no">4227</span><span id="line-4227">        // throw DoNotRetryIOException instead of IllegalArgumentException</span>
-<span class="source-line-no">4228</span><span id="line-4228">        throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");</span>
-<span class="source-line-no">4229</span><span id="line-4229">      }</span>
-<span class="source-line-no">4230</span><span id="line-4230">      return PrivateCellUtil.getValueAsLong(cell);</span>
-<span class="source-line-no">4231</span><span id="line-4231">    }</span>
-<span class="source-line-no">4232</span><span id="line-4232"></span>
-<span class="source-line-no">4233</span><span id="line-4233">    @Override</span>
-<span class="source-line-no">4234</span><span id="line-4234">    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt;</span>
-<span class="source-line-no">4235</span><span id="line-4235">      buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {</span>
-<span class="source-line-no">4236</span><span id="line-4236">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);</span>
-<span class="source-line-no">4237</span><span id="line-4237">      // for MutationBatchOperation, more than one nonce is not allowed</span>
-<span class="source-line-no">4238</span><span id="line-4238">      if (walEdits.size() &gt; 1) {</span>
-<span class="source-line-no">4239</span><span id="line-4239">        throw new IOException("Found multiple nonce keys per batch!");</span>
-<span class="source-line-no">4240</span><span id="line-4240">      }</span>
-<span class="source-line-no">4241</span><span id="line-4241">      return walEdits;</span>
-<span class="source-line-no">4242</span><span id="line-4242">    }</span>
-<span class="source-line-no">4243</span><span id="line-4243"></span>
-<span class="source-line-no">4244</span><span id="line-4244">    /**</span>
-<span class="source-line-no">4245</span><span id="line-4245">     * Here is for HBASE-26993,in order to make the new framework for region replication could work</span>
-<span class="source-line-no">4246</span><span id="line-4246">     * for SKIP_WAL, we save the {@link Mutation} which {@link Mutation#getDurability} is</span>
-<span class="source-line-no">4247</span><span id="line-4247">     * {@link Durability#SKIP_WAL} in miniBatchOp.</span>
-<span class="source-line-no">4248</span><span id="line-4248">     */</span>
-<span class="source-line-no">4249</span><span id="line-4249">    @Override</span>
-<span class="source-line-no">4250</span><span id="line-4250">    protected void cacheSkipWALMutationForRegionReplication(</span>
-<span class="source-line-no">4251</span><span id="line-4251">      MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
-<span class="source-line-no">4252</span><span id="line-4252">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; nonceKeyAndWALEdits,</span>
-<span class="source-line-no">4253</span><span id="line-4253">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
-<span class="source-line-no">4254</span><span id="line-4254">      if (!this.regionReplicateEnable) {</span>
-<span class="source-line-no">4255</span><span id="line-4255">        return;</span>
-<span class="source-line-no">4256</span><span id="line-4256">      }</span>
-<span class="source-line-no">4257</span><span id="line-4257"></span>
-<span class="source-line-no">4258</span><span id="line-4258">      WALEdit walEditForReplicateIfExistsSkipWAL =</span>
-<span class="source-line-no">4259</span><span id="line-4259">        miniBatchOp.getWalEditForReplicateIfExistsSkipWAL();</span>
-<span class="source-line-no">4260</span><span id="line-4260">      /**</span>
-<span class="source-line-no">4261</span><span id="line-4261">       * When there is a SKIP_WAL {@link Mutation},we create a new {@link WALEdit} for replicating</span>
-<span class="source-line-no">4262</span><span id="line-4262">       * to region replica,first we fill the existing {@link WALEdit} to it and then add the</span>
-<span class="source-line-no">4263</span><span id="line-4263">       * {@link Mutation} which is SKIP_WAL to it.</span>
-<span class="source-line-no">4264</span><span id="line-4264">       */</span>
-<span class="source-line-no">4265</span><span id="line-4265">      if (walEditForReplicateIfExistsSkipWAL == null) {</span>
-<span class="source-line-no">4266</span><span id="line-4266">        walEditForReplicateIfExistsSkipWAL =</span>
-<span class="source-line-no">4267</span><span id="line-4267">          this.createWALEditForReplicateSkipWAL(miniBatchOp, nonceKeyAndWALEdits);</span>
-<span class="source-line-no">4268</span><span id="line-4268">        miniBatchOp.setWalEditForReplicateIfExistsSkipWAL(walEditForReplicateIfExistsSkipWAL);</span>
-<span class="source-line-no">4269</span><span id="line-4269">      }</span>
-<span class="source-line-no">4270</span><span id="line-4270">      WALEditInternalHelper.addMap(walEditForReplicateIfExistsSkipWAL, familyCellMap);</span>
-<span class="source-line-no">4271</span><span id="line-4271"></span>
-<span class="source-line-no">4272</span><span id="line-4272">    }</span>
-<span class="source-line-no">4273</span><span id="line-4273"></span>
-<span class="source-line-no">4274</span><span id="line-4274">    private WALEdit createWALEditForReplicateSkipWAL(</span>
-<span class="source-line-no">4275</span><span id="line-4275">      MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
-<span class="source-line-no">4276</span><span id="line-4276">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; nonceKeyAndWALEdits) {</span>
-<span class="source-line-no">4277</span><span id="line-4277">      if (nonceKeyAndWALEdits.isEmpty()) {</span>
-<span class="source-line-no">4278</span><span id="line-4278">        return this.createWALEdit(miniBatchOp);</span>
-<span class="source-line-no">4279</span><span id="line-4279">      }</span>
-<span class="source-line-no">4280</span><span id="line-4280">      // for MutationBatchOperation, more than one nonce is not allowed</span>
-<span class="source-line-no">4281</span><span id="line-4281">      assert nonceKeyAndWALEdits.size() == 1;</span>
-<span class="source-line-no">4282</span><span id="line-4282">      WALEdit currentWALEdit = nonceKeyAndWALEdits.get(0).getSecond();</span>
-<span class="source-line-no">4283</span><span id="line-4283">      return new WALEdit(currentWALEdit);</span>
+<span class="source-line-no">4154</span><span id="line-4154">        }</span>
+<span class="source-line-no">4155</span><span id="line-4155">      }</span>
+<span class="source-line-no">4156</span><span id="line-4156">      return ret;</span>
+<span class="source-line-no">4157</span><span id="line-4157">    }</span>
+<span class="source-line-no">4158</span><span id="line-4158"></span>
+<span class="source-line-no">4159</span><span id="line-4159">    /**</span>
+<span class="source-line-no">4160</span><span id="line-4160">     * Reckon the Cells to apply to WAL, memstore, and to return to the Client in passed column</span>
+<span class="source-line-no">4161</span><span id="line-4161">     * family/Store. Does Get of current value and then adds passed in deltas for this Store</span>
+<span class="source-line-no">4162</span><span id="line-4162">     * returning the result.</span>
+<span class="source-line-no">4163</span><span id="line-4163">     * @param mutation The encompassing Mutation object</span>
+<span class="source-line-no">4164</span><span id="line-4164">     * @param deltas   Changes to apply to this Store; either increment amount or data to append</span>
+<span class="source-line-no">4165</span><span id="line-4165">     * @param results  In here we accumulate all the Cells we are to return to the client. If null,</span>
+<span class="source-line-no">4166</span><span id="line-4166">     *                 client doesn't want results returned.</span>
+<span class="source-line-no">4167</span><span id="line-4167">     * @return Resulting Cells after &lt;code&gt;deltas&lt;/code&gt; have been applied to current values. Side</span>
+<span class="source-line-no">4168</span><span id="line-4168">     *         effect is our filling out of the &lt;code&gt;results&lt;/code&gt; List.</span>
+<span class="source-line-no">4169</span><span id="line-4169">     */</span>
+<span class="source-line-no">4170</span><span id="line-4170">    private List&lt;ExtendedCell&gt; reckonDeltasByStore(HStore store, Mutation mutation, long now,</span>
+<span class="source-line-no">4171</span><span id="line-4171">      List&lt;ExtendedCell&gt; deltas, List&lt;ExtendedCell&gt; results) throws IOException {</span>
+<span class="source-line-no">4172</span><span id="line-4172">      assert mutation instanceof Increment || mutation instanceof Append;</span>
+<span class="source-line-no">4173</span><span id="line-4173">      byte[] columnFamily = store.getColumnFamilyDescriptor().getName();</span>
+<span class="source-line-no">4174</span><span id="line-4174">      List&lt;Pair&lt;ExtendedCell, ExtendedCell&gt;&gt; cellPairs = new ArrayList&lt;&gt;(deltas.size());</span>
+<span class="source-line-no">4175</span><span id="line-4175"></span>
+<span class="source-line-no">4176</span><span id="line-4176">      // Sort the cells so that they match the order that they appear in the Get results.</span>
+<span class="source-line-no">4177</span><span id="line-4177">      // Otherwise, we won't be able to find the existing values if the cells are not specified</span>
+<span class="source-line-no">4178</span><span id="line-4178">      // in order by the client since cells are in an array list.</span>
+<span class="source-line-no">4179</span><span id="line-4179">      deltas.sort(store.getComparator());</span>
+<span class="source-line-no">4180</span><span id="line-4180"></span>
+<span class="source-line-no">4181</span><span id="line-4181">      // Get previous values for all columns in this family.</span>
+<span class="source-line-no">4182</span><span id="line-4182">      Get get = new Get(mutation.getRow());</span>
+<span class="source-line-no">4183</span><span id="line-4183">      for (ExtendedCell cell : deltas) {</span>
+<span class="source-line-no">4184</span><span id="line-4184">        get.addColumn(columnFamily, CellUtil.cloneQualifier(cell));</span>
+<span class="source-line-no">4185</span><span id="line-4185">      }</span>
+<span class="source-line-no">4186</span><span id="line-4186">      TimeRange tr;</span>
+<span class="source-line-no">4187</span><span id="line-4187">      if (mutation instanceof Increment) {</span>
+<span class="source-line-no">4188</span><span id="line-4188">        tr = ((Increment) mutation).getTimeRange();</span>
+<span class="source-line-no">4189</span><span id="line-4189">      } else {</span>
+<span class="source-line-no">4190</span><span id="line-4190">        tr = ((Append) mutation).getTimeRange();</span>
+<span class="source-line-no">4191</span><span id="line-4191">      }</span>
+<span class="source-line-no">4192</span><span id="line-4192"></span>
+<span class="source-line-no">4193</span><span id="line-4193">      if (tr != null) {</span>
+<span class="source-line-no">4194</span><span id="line-4194">        get.setTimeRange(tr.getMin(), tr.getMax());</span>
+<span class="source-line-no">4195</span><span id="line-4195">      }</span>
+<span class="source-line-no">4196</span><span id="line-4196"></span>
+<span class="source-line-no">4197</span><span id="line-4197">      try (RegionScanner scanner = region.getScanner(new Scan(get))) {</span>
+<span class="source-line-no">4198</span><span id="line-4198">        // NOTE: Please don't use HRegion.get() instead,</span>
+<span class="source-line-no">4199</span><span id="line-4199">        // because it will copy cells to heap. See HBASE-26036</span>
+<span class="source-line-no">4200</span><span id="line-4200">        List&lt;ExtendedCell&gt; currentValues = new ArrayList&lt;&gt;();</span>
+<span class="source-line-no">4201</span><span id="line-4201">        scanner.next(currentValues);</span>
+<span class="source-line-no">4202</span><span id="line-4202">        // Iterate the input columns and update existing values if they were found, otherwise</span>
+<span class="source-line-no">4203</span><span id="line-4203">        // add new column initialized to the delta amount</span>
+<span class="source-line-no">4204</span><span id="line-4204">        int currentValuesIndex = 0;</span>
+<span class="source-line-no">4205</span><span id="line-4205">        for (int i = 0; i &lt; deltas.size(); i++) {</span>
+<span class="source-line-no">4206</span><span id="line-4206">          ExtendedCell delta = deltas.get(i);</span>
+<span class="source-line-no">4207</span><span id="line-4207">          ExtendedCell currentValue = null;</span>
+<span class="source-line-no">4208</span><span id="line-4208">          if (</span>
+<span class="source-line-no">4209</span><span id="line-4209">            currentValuesIndex &lt; currentValues.size()</span>
+<span class="source-line-no">4210</span><span id="line-4210">              &amp;&amp; CellUtil.matchingQualifier(currentValues.get(currentValuesIndex), delta)</span>
+<span class="source-line-no">4211</span><span id="line-4211">          ) {</span>
+<span class="source-line-no">4212</span><span id="line-4212">            currentValue = currentValues.get(currentValuesIndex);</span>
+<span class="source-line-no">4213</span><span id="line-4213">            if (i &lt; (deltas.size() - 1) &amp;&amp; !CellUtil.matchingQualifier(delta, deltas.get(i + 1))) {</span>
+<span class="source-line-no">4214</span><span id="line-4214">              currentValuesIndex++;</span>
+<span class="source-line-no">4215</span><span id="line-4215">            }</span>
+<span class="source-line-no">4216</span><span id="line-4216">          }</span>
+<span class="source-line-no">4217</span><span id="line-4217">          // Switch on whether this an increment or an append building the new Cell to apply.</span>
+<span class="source-line-no">4218</span><span id="line-4218">          ExtendedCell newCell;</span>
+<span class="source-line-no">4219</span><span id="line-4219">          if (mutation instanceof Increment) {</span>
+<span class="source-line-no">4220</span><span id="line-4220">            long deltaAmount = getLongValue(delta);</span>
+<span class="source-line-no">4221</span><span id="line-4221">            final long newValue =</span>
+<span class="source-line-no">4222</span><span id="line-4222">              currentValue == null ? deltaAmount : getLongValue(currentValue) + deltaAmount;</span>
+<span class="source-line-no">4223</span><span id="line-4223">            newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation,</span>
+<span class="source-line-no">4224</span><span id="line-4224">              (oldCell) -&gt; Bytes.toBytes(newValue));</span>
+<span class="source-line-no">4225</span><span id="line-4225">          } else {</span>
+<span class="source-line-no">4226</span><span id="line-4226">            newCell = reckonDelta(delta, currentValue, columnFamily, now, mutation,</span>
+<span class="source-line-no">4227</span><span id="line-4227">              (oldCell) -&gt; ByteBuffer</span>
+<span class="source-line-no">4228</span><span id="line-4228">                .wrap(new byte[delta.getValueLength() + oldCell.getValueLength()])</span>
+<span class="source-line-no">4229</span><span id="line-4229">                .put(oldCell.getValueArray(), oldCell.getValueOffset(), oldCell.getValueLength())</span>
+<span class="source-line-no">4230</span><span id="line-4230">                .put(delta.getValueArray(), delta.getValueOffset(), delta.getValueLength())</span>
+<span class="source-line-no">4231</span><span id="line-4231">                .array());</span>
+<span class="source-line-no">4232</span><span id="line-4232">          }</span>
+<span class="source-line-no">4233</span><span id="line-4233">          if (region.maxCellSize &gt; 0) {</span>
+<span class="source-line-no">4234</span><span id="line-4234">            int newCellSize = PrivateCellUtil.estimatedSerializedSizeOf(newCell);</span>
+<span class="source-line-no">4235</span><span id="line-4235">            if (newCellSize &gt; region.maxCellSize) {</span>
+<span class="source-line-no">4236</span><span id="line-4236">              String msg = "Cell with size " + newCellSize + " exceeds limit of "</span>
+<span class="source-line-no">4237</span><span id="line-4237">                + region.maxCellSize + " bytes in region " + this;</span>
+<span class="source-line-no">4238</span><span id="line-4238">              LOG.debug(msg);</span>
+<span class="source-line-no">4239</span><span id="line-4239">              throw new DoNotRetryIOException(msg);</span>
+<span class="source-line-no">4240</span><span id="line-4240">            }</span>
+<span class="source-line-no">4241</span><span id="line-4241">          }</span>
+<span class="source-line-no">4242</span><span id="line-4242">          cellPairs.add(new Pair&lt;&gt;(currentValue, newCell));</span>
+<span class="source-line-no">4243</span><span id="line-4243">          // Add to results to get returned to the Client. If null, cilent does not want results.</span>
+<span class="source-line-no">4244</span><span id="line-4244">          if (results != null) {</span>
+<span class="source-line-no">4245</span><span id="line-4245">            results.add(newCell);</span>
+<span class="source-line-no">4246</span><span id="line-4246">          }</span>
+<span class="source-line-no">4247</span><span id="line-4247">        }</span>
+<span class="source-line-no">4248</span><span id="line-4248">        // Give coprocessors a chance to update the new cells before apply to WAL or memstore</span>
+<span class="source-line-no">4249</span><span id="line-4249">        if (region.coprocessorHost != null) {</span>
+<span class="source-line-no">4250</span><span id="line-4250">          // Here the operation must be increment or append.</span>
+<span class="source-line-no">4251</span><span id="line-4251">          cellPairs = mutation instanceof Increment</span>
+<span class="source-line-no">4252</span><span id="line-4252">            ? region.coprocessorHost.postIncrementBeforeWAL(mutation, (List) cellPairs)</span>
+<span class="source-line-no">4253</span><span id="line-4253">            : region.coprocessorHost.postAppendBeforeWAL(mutation, (List) cellPairs);</span>
+<span class="source-line-no">4254</span><span id="line-4254">        }</span>
+<span class="source-line-no">4255</span><span id="line-4255">      }</span>
+<span class="source-line-no">4256</span><span id="line-4256">      return cellPairs.stream().map(Pair::getSecond).collect(Collectors.toList());</span>
+<span class="source-line-no">4257</span><span id="line-4257">    }</span>
+<span class="source-line-no">4258</span><span id="line-4258"></span>
+<span class="source-line-no">4259</span><span id="line-4259">    private static ExtendedCell reckonDelta(final ExtendedCell delta,</span>
+<span class="source-line-no">4260</span><span id="line-4260">      final ExtendedCell currentCell, final byte[] columnFamily, final long now, Mutation mutation,</span>
+<span class="source-line-no">4261</span><span id="line-4261">      Function&lt;ExtendedCell, byte[]&gt; supplier) throws IOException {</span>
+<span class="source-line-no">4262</span><span id="line-4262">      // Forward any tags found on the delta.</span>
+<span class="source-line-no">4263</span><span id="line-4263">      List&lt;Tag&gt; tags = TagUtil.carryForwardTags(delta);</span>
+<span class="source-line-no">4264</span><span id="line-4264">      if (currentCell != null) {</span>
+<span class="source-line-no">4265</span><span id="line-4265">        tags = TagUtil.carryForwardTags(tags, currentCell);</span>
+<span class="source-line-no">4266</span><span id="line-4266">        tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());</span>
+<span class="source-line-no">4267</span><span id="line-4267">        byte[] newValue = supplier.apply(currentCell);</span>
+<span class="source-line-no">4268</span><span id="line-4268">        return ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)</span>
+<span class="source-line-no">4269</span><span id="line-4269">          .setRow(mutation.getRow(), 0, mutation.getRow().length)</span>
+<span class="source-line-no">4270</span><span id="line-4270">          .setFamily(columnFamily, 0, columnFamily.length)</span>
+<span class="source-line-no">4271</span><span id="line-4271">          // copy the qualifier if the cell is located in shared memory.</span>
+<span class="source-line-no">4272</span><span id="line-4272">          .setQualifier(CellUtil.cloneQualifier(delta))</span>
+<span class="source-line-no">4273</span><span id="line-4273">          .setTimestamp(Math.max(currentCell.getTimestamp() + 1, now))</span>
+<span class="source-line-no">4274</span><span id="line-4274">          .setType(KeyValue.Type.Put.getCode()).setValue(newValue, 0, newValue.length)</span>
+<span class="source-line-no">4275</span><span id="line-4275">          .setTags(TagUtil.fromList(tags)).build();</span>
+<span class="source-line-no">4276</span><span id="line-4276">      } else {</span>
+<span class="source-line-no">4277</span><span id="line-4277">        tags = TagUtil.carryForwardTTLTag(tags, mutation.getTTL());</span>
+<span class="source-line-no">4278</span><span id="line-4278">        PrivateCellUtil.updateLatestStamp(delta, now);</span>
+<span class="source-line-no">4279</span><span id="line-4279">        ExtendedCell deltaCell = (ExtendedCell) delta;</span>
+<span class="source-line-no">4280</span><span id="line-4280">        return CollectionUtils.isEmpty(tags)</span>
+<span class="source-line-no">4281</span><span id="line-4281">          ? deltaCell</span>
+<span class="source-line-no">4282</span><span id="line-4282">          : PrivateCellUtil.createCell(deltaCell, tags);</span>
+<span class="source-line-no">4283</span><span id="line-4283">      }</span>
 <span class="source-line-no">4284</span><span id="line-4284">    }</span>
 <span class="source-line-no">4285</span><span id="line-4285"></span>
-<span class="source-line-no">4286</span><span id="line-4286">    @Override</span>
-<span class="source-line-no">4287</span><span id="line-4287">    protected void addNonSkipWALMutationsToWALEdit(</span>
-<span class="source-line-no">4288</span><span id="line-4288">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, WALEdit walEdit,</span>
-<span class="source-line-no">4289</span><span id="line-4289">      List&lt;ExtendedCell&gt; cellsFromCP, Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
-<span class="source-line-no">4290</span><span id="line-4290">      super.addNonSkipWALMutationsToWALEdit(miniBatchOp, walEdit, cellsFromCP, familyCellMap);</span>
-<span class="source-line-no">4291</span><span id="line-4291">      WALEdit walEditForReplicateIfExistsSkipWAL =</span>
-<span class="source-line-no">4292</span><span id="line-4292">        miniBatchOp.getWalEditForReplicateIfExistsSkipWAL();</span>
-<span class="source-line-no">4293</span><span id="line-4293">      if (walEditForReplicateIfExistsSkipWAL == null) {</span>
-<span class="source-line-no">4294</span><span id="line-4294">        return;</span>
-<span class="source-line-no">4295</span><span id="line-4295">      }</span>
-<span class="source-line-no">4296</span><span id="line-4296">      /**</span>
-<span class="source-line-no">4297</span><span id="line-4297">       * When walEditForReplicateIfExistsSkipWAL is not null,it means there exists SKIP_WAL</span>
-<span class="source-line-no">4298</span><span id="line-4298">       * {@link Mutation} and we create a new {@link WALEdit} in</span>
-<span class="source-line-no">4299</span><span id="line-4299">       * {@link MutationBatchOperation#cacheSkipWALMutationForReplicateRegionReplica} for</span>
-<span class="source-line-no">4300</span><span id="line-4300">       * replicating to region replica, so here we also add non SKIP_WAL{@link Mutation}s to</span>
-<span class="source-line-no">4301</span><span id="line-4301">       * walEditForReplicateIfExistsSkipWAL.</span>
-<span class="source-line-no">4302</span><span id="line-4302">       */</span>
-<span class="source-line-no">4303</span><span id="line-4303">      doAddCellsToWALEdit(walEditForReplicateIfExistsSkipWAL, cellsFromCP, familyCellMap);</span>
-<span class="source-line-no">4304</span><span id="line-4304">    }</span>
-<span class="source-line-no">4305</span><span id="line-4305"></span>
-<span class="source-line-no">4306</span><span id="line-4306">    @Override</span>
-<span class="source-line-no">4307</span><span id="line-4307">    public WriteEntry writeMiniBatchOperationsToMemStore(</span>
-<span class="source-line-no">4308</span><span id="line-4308">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry,</span>
-<span class="source-line-no">4309</span><span id="line-4309">      long now) throws IOException {</span>
-<span class="source-line-no">4310</span><span id="line-4310">      boolean newWriteEntry = false;</span>
-<span class="source-line-no">4311</span><span id="line-4311">      if (writeEntry == null) {</span>
-<span class="source-line-no">4312</span><span id="line-4312">        writeEntry = region.mvcc.begin();</span>
-<span class="source-line-no">4313</span><span id="line-4313">        newWriteEntry = true;</span>
-<span class="source-line-no">4314</span><span id="line-4314">      }</span>
-<span class="source-line-no">4315</span><span id="line-4315">      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());</span>
-<span class="source-line-no">4316</span><span id="line-4316">      if (newWriteEntry) {</span>
-<span class="source-line-no">4317</span><span id="line-4317">        /**</span>
-<span class="source-line-no">4318</span><span id="line-4318">         * Here is for HBASE-26993 case 2,all {@link Mutation}s are {@link Durability#SKIP_WAL}. In</span>
-<span class="source-line-no">4319</span><span id="line-4319">         * order to make the new framework for region replication could work for SKIP_WAL,because</span>
-<span class="source-line-no">4320</span><span id="line-4320">         * there is no {@link RegionReplicationSink#add} attached in {@link HRegion#doWALAppend},so</span>
-<span class="source-line-no">4321</span><span id="line-4321">         * here we get {@link WALEdit} from</span>
-<span class="source-line-no">4322</span><span id="line-4322">         * {@link MiniBatchOperationInProgress#getWalEditForReplicateIfExistsSkipWAL} and attach</span>
-<span class="source-line-no">4323</span><span id="line-4323">         * {@link RegionReplicationSink#add} to the new mvcc writeEntry.</span>
-<span class="source-line-no">4324</span><span id="line-4324">         */</span>
-<span class="source-line-no">4325</span><span id="line-4325">        attachRegionReplicationToMVCCEntry(miniBatchOp, writeEntry, now);</span>
-<span class="source-line-no">4326</span><span id="line-4326">      }</span>
-<span class="source-line-no">4327</span><span id="line-4327">      return writeEntry;</span>
-<span class="source-line-no">4328</span><span id="line-4328">    }</span>
-<span class="source-line-no">4329</span><span id="line-4329"></span>
-<span class="source-line-no">4330</span><span id="line-4330">    private WALKeyImpl createWALKey(long now) {</span>
-<span class="source-line-no">4331</span><span id="line-4331">      // for MutationBatchOperation,isReplay is false.</span>
-<span class="source-line-no">4332</span><span id="line-4332">      return this.region.createWALKeyForWALAppend(false, this, now, this.nonceGroup, this.nonce);</span>
-<span class="source-line-no">4333</span><span id="line-4333">    }</span>
+<span class="source-line-no">4286</span><span id="line-4286">    /** Returns Get the long out of the passed in Cell */</span>
+<span class="source-line-no">4287</span><span id="line-4287">    private static long getLongValue(final Cell cell) throws DoNotRetryIOException {</span>
+<span class="source-line-no">4288</span><span id="line-4288">      int len = cell.getValueLength();</span>
+<span class="source-line-no">4289</span><span id="line-4289">      if (len != Bytes.SIZEOF_LONG) {</span>
+<span class="source-line-no">4290</span><span id="line-4290">        // throw DoNotRetryIOException instead of IllegalArgumentException</span>
+<span class="source-line-no">4291</span><span id="line-4291">        throw new DoNotRetryIOException("Field is not a long, it's " + len + " bytes wide");</span>
+<span class="source-line-no">4292</span><span id="line-4292">      }</span>
+<span class="source-line-no">4293</span><span id="line-4293">      return PrivateCellUtil.getValueAsLong(cell);</span>
+<span class="source-line-no">4294</span><span id="line-4294">    }</span>
+<span class="source-line-no">4295</span><span id="line-4295"></span>
+<span class="source-line-no">4296</span><span id="line-4296">    @Override</span>
+<span class="source-line-no">4297</span><span id="line-4297">    public List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt;</span>
+<span class="source-line-no">4298</span><span id="line-4298">      buildWALEdits(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp) throws IOException {</span>
+<span class="source-line-no">4299</span><span id="line-4299">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = super.buildWALEdits(miniBatchOp);</span>
+<span class="source-line-no">4300</span><span id="line-4300">      // for MutationBatchOperation, more than one nonce is not allowed</span>
+<span class="source-line-no">4301</span><span id="line-4301">      if (walEdits.size() &gt; 1) {</span>
+<span class="source-line-no">4302</span><span id="line-4302">        throw new IOException("Found multiple nonce keys per batch!");</span>
+<span class="source-line-no">4303</span><span id="line-4303">      }</span>
+<span class="source-line-no">4304</span><span id="line-4304">      return walEdits;</span>
+<span class="source-line-no">4305</span><span id="line-4305">    }</span>
+<span class="source-line-no">4306</span><span id="line-4306"></span>
+<span class="source-line-no">4307</span><span id="line-4307">    /**</span>
+<span class="source-line-no">4308</span><span id="line-4308">     * Here is for HBASE-26993,in order to make the new framework for region replication could work</span>
+<span class="source-line-no">4309</span><span id="line-4309">     * for SKIP_WAL, we save the {@link Mutation} which {@link Mutation#getDurability} is</span>
+<span class="source-line-no">4310</span><span id="line-4310">     * {@link Durability#SKIP_WAL} in miniBatchOp.</span>
+<span class="source-line-no">4311</span><span id="line-4311">     */</span>
+<span class="source-line-no">4312</span><span id="line-4312">    @Override</span>
+<span class="source-line-no">4313</span><span id="line-4313">    protected void cacheSkipWALMutationForRegionReplication(</span>
+<span class="source-line-no">4314</span><span id="line-4314">      MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
+<span class="source-line-no">4315</span><span id="line-4315">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; nonceKeyAndWALEdits,</span>
+<span class="source-line-no">4316</span><span id="line-4316">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
+<span class="source-line-no">4317</span><span id="line-4317">      if (!this.regionReplicateEnable) {</span>
+<span class="source-line-no">4318</span><span id="line-4318">        return;</span>
+<span class="source-line-no">4319</span><span id="line-4319">      }</span>
+<span class="source-line-no">4320</span><span id="line-4320"></span>
+<span class="source-line-no">4321</span><span id="line-4321">      WALEdit walEditForReplicateIfExistsSkipWAL =</span>
+<span class="source-line-no">4322</span><span id="line-4322">        miniBatchOp.getWalEditForReplicateIfExistsSkipWAL();</span>
+<span class="source-line-no">4323</span><span id="line-4323">      /**</span>
+<span class="source-line-no">4324</span><span id="line-4324">       * When there is a SKIP_WAL {@link Mutation},we create a new {@link WALEdit} for replicating</span>
+<span class="source-line-no">4325</span><span id="line-4325">       * to region replica,first we fill the existing {@link WALEdit} to it and then add the</span>
+<span class="source-line-no">4326</span><span id="line-4326">       * {@link Mutation} which is SKIP_WAL to it.</span>
+<span class="source-line-no">4327</span><span id="line-4327">       */</span>
+<span class="source-line-no">4328</span><span id="line-4328">      if (walEditForReplicateIfExistsSkipWAL == null) {</span>
+<span class="source-line-no">4329</span><span id="line-4329">        walEditForReplicateIfExistsSkipWAL =</span>
+<span class="source-line-no">4330</span><span id="line-4330">          this.createWALEditForReplicateSkipWAL(miniBatchOp, nonceKeyAndWALEdits);</span>
+<span class="source-line-no">4331</span><span id="line-4331">        miniBatchOp.setWalEditForReplicateIfExistsSkipWAL(walEditForReplicateIfExistsSkipWAL);</span>
+<span class="source-line-no">4332</span><span id="line-4332">      }</span>
+<span class="source-line-no">4333</span><span id="line-4333">      WALEditInternalHelper.addMap(walEditForReplicateIfExistsSkipWAL, familyCellMap);</span>
 <span class="source-line-no">4334</span><span id="line-4334"></span>
-<span class="source-line-no">4335</span><span id="line-4335">    /**</span>
-<span class="source-line-no">4336</span><span id="line-4336">     * Create {@link WALKeyImpl} and get {@link WALEdit} from miniBatchOp and attach</span>
-<span class="source-line-no">4337</span><span id="line-4337">     * {@link RegionReplicationSink#add} to the mvccWriteEntry.</span>
-<span class="source-line-no">4338</span><span id="line-4338">     */</span>
-<span class="source-line-no">4339</span><span id="line-4339">    private void attachRegionReplicationToMVCCEntry(</span>
-<span class="source-line-no">4340</span><span id="line-4340">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, WriteEntry mvccWriteEntry, long now)</span>
-<span class="source-line-no">4341</span><span id="line-4341">      throws IOException {</span>
-<span class="source-line-no">4342</span><span id="line-4342">      if (!this.regionReplicateEnable) {</span>
-<span class="source-line-no">4343</span><span id="line-4343">        return;</span>
-<span class="source-line-no">4344</span><span id="line-4344">      }</span>
-<span class="source-line-no">4345</span><span id="line-4345">      assert !mvccWriteEntry.getCompletionAction().isPresent();</span>
-<span class="source-line-no">4346</span><span id="line-4346"></span>
-<span class="source-line-no">4347</span><span id="line-4347">      final WALKeyImpl walKey = this.createWALKey(now);</span>
-<span class="source-line-no">4348</span><span id="line-4348">      walKey.setWriteEntry(mvccWriteEntry);</span>
-<span class="source-line-no">4349</span><span id="line-4349">      region.doAttachReplicateRegionReplicaAction(walKey,</span>
-<span class="source-line-no">4350</span><span id="line-4350">        miniBatchOp.getWalEditForReplicateIfExistsSkipWAL(), mvccWriteEntry);</span>
-<span class="source-line-no">4351</span><span id="line-4351">    }</span>
-<span class="source-line-no">4352</span><span id="line-4352"></span>
-<span class="source-line-no">4353</span><span id="line-4353">    @Override</span>
-<span class="source-line-no">4354</span><span id="line-4354">    public void completeMiniBatchOperations(</span>
-<span class="source-line-no">4355</span><span id="line-4355">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)</span>
-<span class="source-line-no">4356</span><span id="line-4356">      throws IOException {</span>
-<span class="source-line-no">4357</span><span id="line-4357">      // TODO: can it be done after completing mvcc?</span>
-<span class="source-line-no">4358</span><span id="line-4358">      // calling the post CP hook for batch mutation</span>
-<span class="source-line-no">4359</span><span id="line-4359">      if (region.coprocessorHost != null) {</span>
-<span class="source-line-no">4360</span><span id="line-4360">        region.coprocessorHost.postBatchMutate(miniBatchOp);</span>
-<span class="source-line-no">4361</span><span id="line-4361">      }</span>
-<span class="source-line-no">4362</span><span id="line-4362">      super.completeMiniBatchOperations(miniBatchOp, writeEntry);</span>
-<span class="source-line-no">4363</span><span id="line-4363"></span>
-<span class="source-line-no">4364</span><span id="line-4364">      if (nonce != HConstants.NO_NONCE) {</span>
-<span class="source-line-no">4365</span><span id="line-4365">        if (region.rsServices != null &amp;&amp; region.rsServices.getNonceManager() != null) {</span>
-<span class="source-line-no">4366</span><span id="line-4366">          region.rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,</span>
-<span class="source-line-no">4367</span><span id="line-4367">            writeEntry.getWriteNumber());</span>
-<span class="source-line-no">4368</span><span id="line-4368">        }</span>
-<span class="source-line-no">4369</span><span id="line-4369">      }</span>
-<span class="source-line-no">4370</span><span id="line-4370">    }</span>
-<span class="source-line-no">4371</span><span id="line-4371"></span>
-<span class="source-line-no">4372</span><span id="line-4372">    @Override</span>
-<span class="source-line-no">4373</span><span id="line-4373">    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
-<span class="source-line-no">4374</span><span id="line-4374">      final WALEdit walEdit, boolean success) throws IOException {</span>
-<span class="source-line-no">4375</span><span id="line-4375"></span>
-<span class="source-line-no">4376</span><span id="line-4376">      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);</span>
-<span class="source-line-no">4377</span><span id="line-4377">      if (miniBatchOp != null) {</span>
-<span class="source-line-no">4378</span><span id="line-4378">        // synced so that the coprocessor contract is adhered to.</span>
-<span class="source-line-no">4379</span><span id="line-4379">        if (region.coprocessorHost != null) {</span>
-<span class="source-line-no">4380</span><span id="line-4380">          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {</span>
-<span class="source-line-no">4381</span><span id="line-4381">            // only for successful puts/deletes/increments/appends</span>
-<span class="source-line-no">4382</span><span id="line-4382">            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {</span>
-<span class="source-line-no">4383</span><span id="line-4383">              Mutation m = getMutation(i);</span>
-<span class="source-line-no">4384</span><span id="line-4384">              if (m instanceof Put) {</span>
-<span class="source-line-no">4385</span><span id="line-4385">                region.coprocessorHost.postPut((Put) m, walEdit);</span>
-<span class="source-line-no">4386</span><span id="line-4386">              } else if (m instanceof Delete) {</span>
-<span class="source-line-no">4387</span><span id="line-4387">                region.coprocessorHost.postDelete((Delete) m, walEdit);</span>
-<span class="source-line-no">4388</span><span id="line-4388">              } else if (m instanceof Increment) {</span>
-<span class="source-line-no">4389</span><span id="line-4389">                Result result =</span>
-<span class="source-line-no">4390</span><span id="line-4390">                  region.getCoprocessorHost().postIncrement((Increment) m, results[i], walEdit);</span>
-<span class="source-line-no">4391</span><span id="line-4391">                if (result != results[i]) {</span>
-<span class="source-line-no">4392</span><span id="line-4392">                  retCodeDetails[i] =</span>
-<span class="source-line-no">4393</span><span id="line-4393">                    new OperationStatus(retCodeDetails[i].getOperationStatusCode(), result);</span>
-<span class="source-line-no">4394</span><span id="line-4394">                }</span>
-<span class="source-line-no">4395</span><span id="line-4395">              } else if (m instanceof Append) {</span>
-<span class="source-line-no">4396</span><span id="line-4396">                Result result =</span>
-<span class="source-line-no">4397</span><span id="line-4397">                  region.getCoprocessorHost().postAppend((Append) m, results[i], walEdit);</span>
-<span class="source-line-no">4398</span><span id="line-4398">                if (result != results[i]) {</span>
-<span class="source-line-no">4399</span><span id="line-4399">                  retCodeDetails[i] =</span>
-<span class="source-line-no">4400</span><span id="line-4400">                    new OperationStatus(retCodeDetails[i].getOperationStatusCode(), result);</span>
-<span class="source-line-no">4401</span><span id="line-4401">                }</span>
-<span class="source-line-no">4402</span><span id="line-4402">              }</span>
-<span class="source-line-no">4403</span><span id="line-4403">            }</span>
-<span class="source-line-no">4404</span><span id="line-4404">            return true;</span>
-<span class="source-line-no">4405</span><span id="line-4405">          });</span>
-<span class="source-line-no">4406</span><span id="line-4406">        }</span>
-<span class="source-line-no">4407</span><span id="line-4407"></span>
-<span class="source-line-no">4408</span><span id="line-4408">        // For nonce operations</span>
-<span class="source-line-no">4409</span><span id="line-4409">        if (canProceed &amp;&amp; nonce != HConstants.NO_NONCE) {</span>
-<span class="source-line-no">4410</span><span id="line-4410">          boolean[] areAllIncrementsAndAppendsSuccessful = new boolean[] { true };</span>
-<span class="source-line-no">4411</span><span id="line-4411">          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {</span>
-<span class="source-line-no">4412</span><span id="line-4412">            Mutation mutation = getMutation(i);</span>
-<span class="source-line-no">4413</span><span id="line-4413">            if (mutation instanceof Increment || mutation instanceof Append) {</span>
-<span class="source-line-no">4414</span><span id="line-4414">              if (retCodeDetails[i].getOperationStatusCode() != OperationStatusCode.SUCCESS) {</span>
-<span class="source-line-no">4415</span><span id="line-4415">                areAllIncrementsAndAppendsSuccessful[0] = false;</span>
-<span class="source-line-no">4416</span><span id="line-4416">                return false;</span>
-<span class="source-line-no">4417</span><span id="line-4417">              }</span>
-<span class="source-line-no">4418</span><span id="line-4418">            }</span>
-<span class="source-line-no">4419</span><span id="line-4419">            return true;</span>
-<span class="source-line-no">4420</span><span id="line-4420">          });</span>
-<span class="source-line-no">4421</span><span id="line-4421">          endNonceOperation(areAllIncrementsAndAppendsSuccessful[0]);</span>
-<span class="source-line-no">4422</span><span id="line-4422">        }</span>
-<span class="source-line-no">4423</span><span id="line-4423"></span>
-<span class="source-line-no">4424</span><span id="line-4424">        // See if the column families were consistent through the whole thing.</span>
-<span class="source-line-no">4425</span><span id="line-4425">        // if they were then keep them. If they were not then pass a null.</span>
-<span class="source-line-no">4426</span><span id="line-4426">        // null will be treated as unknown.</span>
-<span class="source-line-no">4427</span><span id="line-4427">        // Total time taken might be involving Puts, Deletes, Increments and Appends.</span>
-<span class="source-line-no">4428</span><span id="line-4428">        // Split the time for puts and deletes based on the total number of Puts, Deletes,</span>
-<span class="source-line-no">4429</span><span id="line-4429">        // Increments and Appends.</span>
-<span class="source-line-no">4430</span><span id="line-4430">        if (region.metricsRegion != null) {</span>
-<span class="source-line-no">4431</span><span id="line-4431">          if (miniBatchOp.getNumOfPuts() &gt; 0) {</span>
-<span class="source-line-no">4432</span><span id="line-4432">            // There were some Puts in the batch.</span>
-<span class="source-line-no">4433</span><span id="line-4433">            region.metricsRegion.updatePut();</span>
-<span class="source-line-no">4434</span><span id="line-4434">          }</span>
-<span class="source-line-no">4435</span><span id="line-4435">          if (miniBatchOp.getNumOfDeletes() &gt; 0) {</span>
-<span class="source-line-no">4436</span><span id="line-4436">            // There were some Deletes in the batch.</span>
-<span class="source-line-no">4437</span><span id="line-4437">            region.metricsRegion.updateDelete();</span>
-<span class="source-line-no">4438</span><span id="line-4438">          }</span>
-<span class="source-line-no">4439</span><span id="line-4439">          if (miniBatchOp.getNumOfIncrements() &gt; 0) {</span>
-<span class="source-line-no">4440</span><span id="line-4440">            // There were some Increments in the batch.</span>
-<span class="source-line-no">4441</span><span id="line-4441">            region.metricsRegion.updateIncrement();</span>
-<span class="source-line-no">4442</span><span id="line-4442">          }</span>
-<span class="source-line-no">4443</span><span id="line-4443">          if (miniBatchOp.getNumOfAppends() &gt; 0) {</span>
-<span class="source-line-no">4444</span><span id="line-4444">            // There were some Appends in the batch.</span>
-<span class="source-line-no">4445</span><span id="line-4445">            region.metricsRegion.updateAppend();</span>
-<span class="source-line-no">4446</span><span id="line-4446">          }</span>
-<span class="source-line-no">4447</span><span id="line-4447">        }</span>
-<span class="source-line-no">4448</span><span id="line-4448">      }</span>
-<span class="source-line-no">4449</span><span id="line-4449"></span>
-<span class="source-line-no">4450</span><span id="line-4450">      if (region.coprocessorHost != null) {</span>
-<span class="source-line-no">4451</span><span id="line-4451">        // call the coprocessor hook to do any finalization steps after the put is done</span>
-<span class="source-line-no">4452</span><span id="line-4452">        region.coprocessorHost.postBatchMutateIndispensably(</span>
-<span class="source-line-no">4453</span><span id="line-4453">          miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);</span>
-<span class="source-line-no">4454</span><span id="line-4454">      }</span>
-<span class="source-line-no">4455</span><span id="line-4455">    }</span>
-<span class="source-line-no">4456</span><span id="line-4456"></span>
-<span class="source-line-no">4457</span><span id="line-4457">    /**</span>
-<span class="source-line-no">4458</span><span id="line-4458">     * Runs prePut/preDelete/preIncrement/preAppend coprocessor hook for input mutation in a batch</span>
-<span class="source-line-no">4459</span><span id="line-4459">     * @param metrics Array of 2 ints. index 0: count of puts, index 1: count of deletes, index 2:</span>
-<span class="source-line-no">4460</span><span id="line-4460">     *                count of increments and 3: count of appends</span>
-<span class="source-line-no">4461</span><span id="line-4461">     */</span>
-<span class="source-line-no">4462</span><span id="line-4462">    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)</span>
-<span class="source-line-no">4463</span><span id="line-4463">      throws IOException {</span>
-<span class="source-line-no">4464</span><span id="line-4464">      Mutation m = getMutation(index);</span>
-<span class="source-line-no">4465</span><span id="line-4465">      if (m instanceof Put) {</span>
-<span class="source-line-no">4466</span><span id="line-4466">        if (region.coprocessorHost.prePut((Put) m, walEdit)) {</span>
-<span class="source-line-no">4467</span><span id="line-4467">          // pre hook says skip this Put</span>
-<span class="source-line-no">4468</span><span id="line-4468">          // mark as success and skip in doMiniBatchMutation</span>
-<span class="source-line-no">4469</span><span id="line-4469">          metrics[0]++;</span>
-<span class="source-line-no">4470</span><span id="line-4470">          retCodeDetails[index] = OperationStatus.SUCCESS;</span>
-<span class="source-line-no">4471</span><span id="line-4471">        }</span>
-<span class="source-line-no">4472</span><span id="line-4472">      } else if (m instanceof Delete) {</span>
-<span class="source-line-no">4473</span><span id="line-4473">        Delete curDel = (Delete) m;</span>
-<span class="source-line-no">4474</span><span id="line-4474">        if (curDel.getFamilyCellMap().isEmpty()) {</span>
-<span class="source-line-no">4475</span><span id="line-4475">          // handle deleting a row case</span>
-<span class="source-line-no">4476</span><span id="line-4476">          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.</span>
-<span class="source-line-no">4477</span><span id="line-4477">          // Can this be avoided?</span>
-<span class="source-line-no">4478</span><span id="line-4478">          region.prepareDelete(curDel);</span>
-<span class="source-line-no">4479</span><span id="line-4479">        }</span>
-<span class="source-line-no">4480</span><span id="line-4480">        if (region.coprocessorHost.preDelete(curDel, walEdit)) {</span>
-<span class="source-line-no">4481</span><span id="line-4481">          // pre hook says skip this Delete</span>
-<span class="source-line-no">4482</span><span id="line-4482">          // mark as success and skip in doMiniBatchMutation</span>
-<span class="source-line-no">4483</span><span id="line-4483">          metrics[1]++;</span>
-<span class="source-line-no">4484</span><span id="line-4484">          retCodeDetails[index] = OperationStatus.SUCCESS;</span>
+<span class="source-line-no">4335</span><span id="line-4335">    }</span>
+<span class="source-line-no">4336</span><span id="line-4336"></span>
+<span class="source-line-no">4337</span><span id="line-4337">    private WALEdit createWALEditForReplicateSkipWAL(</span>
+<span class="source-line-no">4338</span><span id="line-4338">      MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
+<span class="source-line-no">4339</span><span id="line-4339">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; nonceKeyAndWALEdits) {</span>
+<span class="source-line-no">4340</span><span id="line-4340">      if (nonceKeyAndWALEdits.isEmpty()) {</span>
+<span class="source-line-no">4341</span><span id="line-4341">        return this.createWALEdit(miniBatchOp);</span>
+<span class="source-line-no">4342</span><span id="line-4342">      }</span>
+<span class="source-line-no">4343</span><span id="line-4343">      // for MutationBatchOperation, more than one nonce is not allowed</span>
+<span class="source-line-no">4344</span><span id="line-4344">      assert nonceKeyAndWALEdits.size() == 1;</span>
+<span class="source-line-no">4345</span><span id="line-4345">      WALEdit currentWALEdit = nonceKeyAndWALEdits.get(0).getSecond();</span>
+<span class="source-line-no">4346</span><span id="line-4346">      return new WALEdit(currentWALEdit);</span>
+<span class="source-line-no">4347</span><span id="line-4347">    }</span>
+<span class="source-line-no">4348</span><span id="line-4348"></span>
+<span class="source-line-no">4349</span><span id="line-4349">    @Override</span>
+<span class="source-line-no">4350</span><span id="line-4350">    protected void addNonSkipWALMutationsToWALEdit(</span>
+<span class="source-line-no">4351</span><span id="line-4351">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, WALEdit walEdit,</span>
+<span class="source-line-no">4352</span><span id="line-4352">      List&lt;ExtendedCell&gt; cellsFromCP, Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
+<span class="source-line-no">4353</span><span id="line-4353">      super.addNonSkipWALMutationsToWALEdit(miniBatchOp, walEdit, cellsFromCP, familyCellMap);</span>
+<span class="source-line-no">4354</span><span id="line-4354">      WALEdit walEditForReplicateIfExistsSkipWAL =</span>
+<span class="source-line-no">4355</span><span id="line-4355">        miniBatchOp.getWalEditForReplicateIfExistsSkipWAL();</span>
+<span class="source-line-no">4356</span><span id="line-4356">      if (walEditForReplicateIfExistsSkipWAL == null) {</span>
+<span class="source-line-no">4357</span><span id="line-4357">        return;</span>
+<span class="source-line-no">4358</span><span id="line-4358">      }</span>
+<span class="source-line-no">4359</span><span id="line-4359">      /**</span>
+<span class="source-line-no">4360</span><span id="line-4360">       * When walEditForReplicateIfExistsSkipWAL is not null,it means there exists SKIP_WAL</span>
+<span class="source-line-no">4361</span><span id="line-4361">       * {@link Mutation} and we create a new {@link WALEdit} in</span>
+<span class="source-line-no">4362</span><span id="line-4362">       * {@link MutationBatchOperation#cacheSkipWALMutationForReplicateRegionReplica} for</span>
+<span class="source-line-no">4363</span><span id="line-4363">       * replicating to region replica, so here we also add non SKIP_WAL{@link Mutation}s to</span>
+<span class="source-line-no">4364</span><span id="line-4364">       * walEditForReplicateIfExistsSkipWAL.</span>
+<span class="source-line-no">4365</span><span id="line-4365">       */</span>
+<span class="source-line-no">4366</span><span id="line-4366">      doAddCellsToWALEdit(walEditForReplicateIfExistsSkipWAL, cellsFromCP, familyCellMap);</span>
+<span class="source-line-no">4367</span><span id="line-4367">    }</span>
+<span class="source-line-no">4368</span><span id="line-4368"></span>
+<span class="source-line-no">4369</span><span id="line-4369">    @Override</span>
+<span class="source-line-no">4370</span><span id="line-4370">    public WriteEntry writeMiniBatchOperationsToMemStore(</span>
+<span class="source-line-no">4371</span><span id="line-4371">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, @Nullable WriteEntry writeEntry,</span>
+<span class="source-line-no">4372</span><span id="line-4372">      long now) throws IOException {</span>
+<span class="source-line-no">4373</span><span id="line-4373">      boolean newWriteEntry = false;</span>
+<span class="source-line-no">4374</span><span id="line-4374">      if (writeEntry == null) {</span>
+<span class="source-line-no">4375</span><span id="line-4375">        writeEntry = region.mvcc.begin();</span>
+<span class="source-line-no">4376</span><span id="line-4376">        newWriteEntry = true;</span>
+<span class="source-line-no">4377</span><span id="line-4377">      }</span>
+<span class="source-line-no">4378</span><span id="line-4378">      super.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry.getWriteNumber());</span>
+<span class="source-line-no">4379</span><span id="line-4379">      if (newWriteEntry) {</span>
+<span class="source-line-no">4380</span><span id="line-4380">        /**</span>
+<span class="source-line-no">4381</span><span id="line-4381">         * Here is for HBASE-26993 case 2,all {@link Mutation}s are {@link Durability#SKIP_WAL}. In</span>
+<span class="source-line-no">4382</span><span id="line-4382">         * order to make the new framework for region replication could work for SKIP_WAL,because</span>
+<span class="source-line-no">4383</span><span id="line-4383">         * there is no {@link RegionReplicationSink#add} attached in {@link HRegion#doWALAppend},so</span>
+<span class="source-line-no">4384</span><span id="line-4384">         * here we get {@link WALEdit} from</span>
+<span class="source-line-no">4385</span><span id="line-4385">         * {@link MiniBatchOperationInProgress#getWalEditForReplicateIfExistsSkipWAL} and attach</span>
+<span class="source-line-no">4386</span><span id="line-4386">         * {@link RegionReplicationSink#add} to the new mvcc writeEntry.</span>
+<span class="source-line-no">4387</span><span id="line-4387">         */</span>
+<span class="source-line-no">4388</span><span id="line-4388">        attachRegionReplicationToMVCCEntry(miniBatchOp, writeEntry, now);</span>
+<span class="source-line-no">4389</span><span id="line-4389">      }</span>
+<span class="source-line-no">4390</span><span id="line-4390">      return writeEntry;</span>
+<span class="source-line-no">4391</span><span id="line-4391">    }</span>
+<span class="source-line-no">4392</span><span id="line-4392"></span>
+<span class="source-line-no">4393</span><span id="line-4393">    private WALKeyImpl createWALKey(long now) {</span>
+<span class="source-line-no">4394</span><span id="line-4394">      // for MutationBatchOperation,isReplay is false.</span>
+<span class="source-line-no">4395</span><span id="line-4395">      return this.region.createWALKeyForWALAppend(false, this, now, this.nonceGroup, this.nonce);</span>
+<span class="source-line-no">4396</span><span id="line-4396">    }</span>
+<span class="source-line-no">4397</span><span id="line-4397"></span>
+<span class="source-line-no">4398</span><span id="line-4398">    /**</span>
+<span class="source-line-no">4399</span><span id="line-4399">     * Create {@link WALKeyImpl} and get {@link WALEdit} from miniBatchOp and attach</span>
+<span class="source-line-no">4400</span><span id="line-4400">     * {@link RegionReplicationSink#add} to the mvccWriteEntry.</span>
+<span class="source-line-no">4401</span><span id="line-4401">     */</span>
+<span class="source-line-no">4402</span><span id="line-4402">    private void attachRegionReplicationToMVCCEntry(</span>
+<span class="source-line-no">4403</span><span id="line-4403">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, WriteEntry mvccWriteEntry, long now)</span>
+<span class="source-line-no">4404</span><span id="line-4404">      throws IOException {</span>
+<span class="source-line-no">4405</span><span id="line-4405">      if (!this.regionReplicateEnable) {</span>
+<span class="source-line-no">4406</span><span id="line-4406">        return;</span>
+<span class="source-line-no">4407</span><span id="line-4407">      }</span>
+<span class="source-line-no">4408</span><span id="line-4408">      assert !mvccWriteEntry.getCompletionAction().isPresent();</span>
+<span class="source-line-no">4409</span><span id="line-4409"></span>
+<span class="source-line-no">4410</span><span id="line-4410">      final WALKeyImpl walKey = this.createWALKey(now);</span>
+<span class="source-line-no">4411</span><span id="line-4411">      walKey.setWriteEntry(mvccWriteEntry);</span>
+<span class="source-line-no">4412</span><span id="line-4412">      region.doAttachReplicateRegionReplicaAction(walKey,</span>
+<span class="source-line-no">4413</span><span id="line-4413">        miniBatchOp.getWalEditForReplicateIfExistsSkipWAL(), mvccWriteEntry);</span>
+<span class="source-line-no">4414</span><span id="line-4414">    }</span>
+<span class="source-line-no">4415</span><span id="line-4415"></span>
+<span class="source-line-no">4416</span><span id="line-4416">    @Override</span>
+<span class="source-line-no">4417</span><span id="line-4417">    public void completeMiniBatchOperations(</span>
+<span class="source-line-no">4418</span><span id="line-4418">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)</span>
+<span class="source-line-no">4419</span><span id="line-4419">      throws IOException {</span>
+<span class="source-line-no">4420</span><span id="line-4420">      // TODO: can it be done after completing mvcc?</span>
+<span class="source-line-no">4421</span><span id="line-4421">      // calling the post CP hook for batch mutation</span>
+<span class="source-line-no">4422</span><span id="line-4422">      if (region.coprocessorHost != null) {</span>
+<span class="source-line-no">4423</span><span id="line-4423">        region.coprocessorHost.postBatchMutate(miniBatchOp);</span>
+<span class="source-line-no">4424</span><span id="line-4424">      }</span>
+<span class="source-line-no">4425</span><span id="line-4425">      super.completeMiniBatchOperations(miniBatchOp, writeEntry);</span>
+<span class="source-line-no">4426</span><span id="line-4426"></span>
+<span class="source-line-no">4427</span><span id="line-4427">      if (nonce != HConstants.NO_NONCE) {</span>
+<span class="source-line-no">4428</span><span id="line-4428">        if (region.rsServices != null &amp;&amp; region.rsServices.getNonceManager() != null) {</span>
+<span class="source-line-no">4429</span><span id="line-4429">          region.rsServices.getNonceManager().addMvccToOperationContext(nonceGroup, nonce,</span>
+<span class="source-line-no">4430</span><span id="line-4430">            writeEntry.getWriteNumber());</span>
+<span class="source-line-no">4431</span><span id="line-4431">        }</span>
+<span class="source-line-no">4432</span><span id="line-4432">      }</span>
+<span class="source-line-no">4433</span><span id="line-4433">    }</span>
+<span class="source-line-no">4434</span><span id="line-4434"></span>
+<span class="source-line-no">4435</span><span id="line-4435">    @Override</span>
+<span class="source-line-no">4436</span><span id="line-4436">    public void doPostOpCleanupForMiniBatch(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
+<span class="source-line-no">4437</span><span id="line-4437">      final WALEdit walEdit, boolean success) throws IOException {</span>
+<span class="source-line-no">4438</span><span id="line-4438"></span>
+<span class="source-line-no">4439</span><span id="line-4439">      super.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, success);</span>
+<span class="source-line-no">4440</span><span id="line-4440">      if (miniBatchOp != null) {</span>
+<span class="source-line-no">4441</span><span id="line-4441">        // synced so that the coprocessor contract is adhered to.</span>
+<span class="source-line-no">4442</span><span id="line-4442">        if (region.coprocessorHost != null) {</span>
+<span class="source-line-no">4443</span><span id="line-4443">          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {</span>
+<span class="source-line-no">4444</span><span id="line-4444">            // only for successful puts/deletes/increments/appends</span>
+<span class="source-line-no">4445</span><span id="line-4445">            if (retCodeDetails[i].getOperationStatusCode() == OperationStatusCode.SUCCESS) {</span>
+<span class="source-line-no">4446</span><span id="line-4446">              Mutation m = getMutation(i);</span>
+<span class="source-line-no">4447</span><span id="line-4447">              if (m instanceof Put) {</span>
+<span class="source-line-no">4448</span><span id="line-4448">                region.coprocessorHost.postPut((Put) m, walEdit);</span>
+<span class="source-line-no">4449</span><span id="line-4449">              } else if (m instanceof Delete) {</span>
+<span class="source-line-no">4450</span><span id="line-4450">                region.coprocessorHost.postDelete((Delete) m, walEdit);</span>
+<span class="source-line-no">4451</span><span id="line-4451">              } else if (m instanceof Increment) {</span>
+<span class="source-line-no">4452</span><span id="line-4452">                Result result =</span>
+<span class="source-line-no">4453</span><span id="line-4453">                  region.getCoprocessorHost().postIncrement((Increment) m, results[i], walEdit);</span>
+<span class="source-line-no">4454</span><span id="line-4454">                if (result != results[i]) {</span>
+<span class="source-line-no">4455</span><span id="line-4455">                  retCodeDetails[i] =</span>
+<span class="source-line-no">4456</span><span id="line-4456">                    new OperationStatus(retCodeDetails[i].getOperationStatusCode(), result);</span>
+<span class="source-line-no">4457</span><span id="line-4457">                }</span>
+<span class="source-line-no">4458</span><span id="line-4458">              } else if (m instanceof Append) {</span>
+<span class="source-line-no">4459</span><span id="line-4459">                Result result =</span>
+<span class="source-line-no">4460</span><span id="line-4460">                  region.getCoprocessorHost().postAppend((Append) m, results[i], walEdit);</span>
+<span class="source-line-no">4461</span><span id="line-4461">                if (result != results[i]) {</span>
+<span class="source-line-no">4462</span><span id="line-4462">                  retCodeDetails[i] =</span>
+<span class="source-line-no">4463</span><span id="line-4463">                    new OperationStatus(retCodeDetails[i].getOperationStatusCode(), result);</span>
+<span class="source-line-no">4464</span><span id="line-4464">                }</span>
+<span class="source-line-no">4465</span><span id="line-4465">              }</span>
+<span class="source-line-no">4466</span><span id="line-4466">            }</span>
+<span class="source-line-no">4467</span><span id="line-4467">            return true;</span>
+<span class="source-line-no">4468</span><span id="line-4468">          });</span>
+<span class="source-line-no">4469</span><span id="line-4469">        }</span>
+<span class="source-line-no">4470</span><span id="line-4470"></span>
+<span class="source-line-no">4471</span><span id="line-4471">        // For nonce operations</span>
+<span class="source-line-no">4472</span><span id="line-4472">        if (canProceed &amp;&amp; nonce != HConstants.NO_NONCE) {</span>
+<span class="source-line-no">4473</span><span id="line-4473">          boolean[] areAllIncrementsAndAppendsSuccessful = new boolean[] { true };</span>
+<span class="source-line-no">4474</span><span id="line-4474">          visitBatchOperations(false, miniBatchOp.getLastIndexExclusive(), (int i) -&gt; {</span>
+<span class="source-line-no">4475</span><span id="line-4475">            Mutation mutation = getMutation(i);</span>
+<span class="source-line-no">4476</span><span id="line-4476">            if (mutation instanceof Increment || mutation instanceof Append) {</span>
+<span class="source-line-no">4477</span><span id="line-4477">              if (retCodeDetails[i].getOperationStatusCode() != OperationStatusCode.SUCCESS) {</span>
+<span class="source-line-no">4478</span><span id="line-4478">                areAllIncrementsAndAppendsSuccessful[0] = false;</span>
+<span class="source-line-no">4479</span><span id="line-4479">                return false;</span>
+<span class="source-line-no">4480</span><span id="line-4480">              }</span>
+<span class="source-line-no">4481</span><span id="line-4481">            }</span>
+<span class="source-line-no">4482</span><span id="line-4482">            return true;</span>
+<span class="source-line-no">4483</span><span id="line-4483">          });</span>
+<span class="source-line-no">4484</span><span id="line-4484">          endNonceOperation(areAllIncrementsAndAppendsSuccessful[0]);</span>
 <span class="source-line-no">4485</span><span id="line-4485">        }</span>
-<span class="source-line-no">4486</span><span id="line-4486">      } else if (m instanceof Increment) {</span>
-<span class="source-line-no">4487</span><span id="line-4487">        Increment increment = (Increment) m;</span>
-<span class="source-line-no">4488</span><span id="line-4488">        Result result = region.coprocessorHost.preIncrement(increment, walEdit);</span>
-<span class="source-line-no">4489</span><span id="line-4489">        if (result != null) {</span>
-<span class="source-line-no">4490</span><span id="line-4490">          // pre hook says skip this Increment</span>
-<span class="source-line-no">4491</span><span id="line-4491">          // mark as success and skip in doMiniBatchMutation</span>
-<span class="source-line-no">4492</span><span id="line-4492">          metrics[2]++;</span>
-<span class="source-line-no">4493</span><span id="line-4493">          retCodeDetails[index] = new OperationStatus(OperationStatusCode.SUCCESS, result);</span>
-<span class="source-line-no">4494</span><span id="line-4494">        }</span>
-<span class="source-line-no">4495</span><span id="line-4495">      } else if (m instanceof Append) {</span>
-<span class="source-line-no">4496</span><span id="line-4496">        Append append = (Append) m;</span>
-<span class="source-line-no">4497</span><span id="line-4497">        Result result = region.coprocessorHost.preAppend(append, walEdit);</span>
-<span class="source-line-no">4498</span><span id="line-4498">        if (result != null) {</span>
-<span class="source-line-no">4499</span><span id="line-4499">          // pre hook says skip this Append</span>
-<span class="source-line-no">4500</span><span id="line-4500">          // mark as success and skip in doMiniBatchMutation</span>
-<span class="source-line-no">4501</span><span id="line-4501">          metrics[3]++;</span>
-<span class="source-line-no">4502</span><span id="line-4502">          retCodeDetails[index] = new OperationStatus(OperationStatusCode.SUCCESS, result);</span>
-<span class="source-line-no">4503</span><span id="line-4503">        }</span>
-<span class="source-line-no">4504</span><span id="line-4504">      } else {</span>
-<span class="source-line-no">4505</span><span id="line-4505">        String msg = "Put/Delete/Increment/Append mutations only supported in a batch";</span>
-<span class="source-line-no">4506</span><span id="line-4506">        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);</span>
-<span class="source-line-no">4507</span><span id="line-4507">        if (isAtomic()) { // fail, atomic means all or none</span>
-<span class="source-line-no">4508</span><span id="line-4508">          throw new IOException(msg);</span>
-<span class="source-line-no">4509</span><span id="line-4509">        }</span>
-<span class="source-line-no">4510</span><span id="line-4510">      }</span>
-<span class="source-line-no">4511</span><span id="line-4511">    }</span>
+<span class="source-line-no">4486</span><span id="line-4486"></span>
+<span class="source-line-no">4487</span><span id="line-4487">        // See if the column families were consistent through the whole thing.</span>
+<span class="source-line-no">4488</span><span id="line-4488">        // if they were then keep them. If they were not then pass a null.</span>
+<span class="source-line-no">4489</span><span id="line-4489">        // null will be treated as unknown.</span>
+<span class="source-line-no">4490</span><span id="line-4490">        // Total time taken might be involving Puts, Deletes, Increments and Appends.</span>
+<span class="source-line-no">4491</span><span id="line-4491">        // Split the time for puts and deletes based on the total number of Puts, Deletes,</span>
+<span class="source-line-no">4492</span><span id="line-4492">        // Increments and Appends.</span>
+<span class="source-line-no">4493</span><span id="line-4493">        if (region.metricsRegion != null) {</span>
+<span class="source-line-no">4494</span><span id="line-4494">          if (miniBatchOp.getNumOfPuts() &gt; 0) {</span>
+<span class="source-line-no">4495</span><span id="line-4495">            // There were some Puts in the batch.</span>
+<span class="source-line-no">4496</span><span id="line-4496">            region.metricsRegion.updatePut();</span>
+<span class="source-line-no">4497</span><span id="line-4497">          }</span>
+<span class="source-line-no">4498</span><span id="line-4498">          if (miniBatchOp.getNumOfDeletes() &gt; 0) {</span>
+<span class="source-line-no">4499</span><span id="line-4499">            // There were some Deletes in the batch.</span>
+<span class="source-line-no">4500</span><span id="line-4500">            region.metricsRegion.updateDelete();</span>
+<span class="source-line-no">4501</span><span id="line-4501">          }</span>
+<span class="source-line-no">4502</span><span id="line-4502">          if (miniBatchOp.getNumOfIncrements() &gt; 0) {</span>
+<span class="source-line-no">4503</span><span id="line-4503">            // There were some Increments in the batch.</span>
+<span class="source-line-no">4504</span><span id="line-4504">            region.metricsRegion.updateIncrement();</span>
+<span class="source-line-no">4505</span><span id="line-4505">          }</span>
+<span class="source-line-no">4506</span><span id="line-4506">          if (miniBatchOp.getNumOfAppends() &gt; 0) {</span>
+<span class="source-line-no">4507</span><span id="line-4507">            // There were some Appends in the batch.</span>
+<span class="source-line-no">4508</span><span id="line-4508">            region.metricsRegion.updateAppend();</span>
+<span class="source-line-no">4509</span><span id="line-4509">          }</span>
+<span class="source-line-no">4510</span><span id="line-4510">        }</span>
+<span class="source-line-no">4511</span><span id="line-4511">      }</span>
 <span class="source-line-no">4512</span><span id="line-4512"></span>
-<span class="source-line-no">4513</span><span id="line-4513">    // TODO Support Increment/Append operations</span>
-<span class="source-line-no">4514</span><span id="line-4514">    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
-<span class="source-line-no">4515</span><span id="line-4515">      final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {</span>
-<span class="source-line-no">4516</span><span id="line-4516">      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {</span>
-<span class="source-line-no">4517</span><span id="line-4517">        // we pass (i - firstIndex) below since the call expects a relative index</span>
-<span class="source-line-no">4518</span><span id="line-4518">        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);</span>
-<span class="source-line-no">4519</span><span id="line-4519">        if (cpMutations == null) {</span>
-<span class="source-line-no">4520</span><span id="line-4520">          return true;</span>
-<span class="source-line-no">4521</span><span id="line-4521">        }</span>
-<span class="source-line-no">4522</span><span id="line-4522">        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.</span>
-<span class="source-line-no">4523</span><span id="line-4523">        Mutation mutation = getMutation(i);</span>
-<span class="source-line-no">4524</span><span id="line-4524">        for (Mutation cpMutation : cpMutations) {</span>
-<span class="source-line-no">4525</span><span id="line-4525">          this.checkAndPrepareMutation(cpMutation, timestamp);</span>
-<span class="source-line-no">4526</span><span id="line-4526"></span>
-<span class="source-line-no">4527</span><span id="line-4527">          // Acquire row locks. If not, the whole batch will fail.</span>
-<span class="source-line-no">4528</span><span id="line-4528">          acquiredRowLocks.add(region.getRowLock(cpMutation.getRow(), true, null));</span>
-<span class="source-line-no">4529</span><span id="line-4529"></span>
-<span class="source-line-no">4530</span><span id="line-4530">          // Returned mutations from coprocessor correspond to the Mutation at index i. We can</span>
-<span class="source-line-no">4531</span><span id="line-4531">          // directly add the cells from those mutations to the familyMaps of this mutation.</span>
-<span class="source-line-no">4532</span><span id="line-4532">          Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; cpFamilyMap =</span>
-<span class="source-line-no">4533</span><span id="line-4533">            ClientInternalHelper.getExtendedFamilyCellMap(cpMutation);</span>
-<span class="source-line-no">4534</span><span id="line-4534">          region.rewriteCellTags(cpFamilyMap, mutation);</span>
-<span class="source-line-no">4535</span><span id="line-4535">          // will get added to the memStore later</span>
-<span class="source-line-no">4536</span><span id="line-4536">          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);</span>
-<span class="source-line-no">4537</span><span id="line-4537"></span>
-<span class="source-line-no">4538</span><span id="line-4538">          // The durability of returned mutation is replaced by the corresponding mutation.</span>
-<span class="source-line-no">4539</span><span id="line-4539">          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the</span>
-<span class="source-line-no">4540</span><span id="line-4540">          // cells of returned mutation.</span>
-<span class="source-line-no">4541</span><span id="line-4541">          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {</span>
-<span class="source-line-no">4542</span><span id="line-4542">            for (List&lt;ExtendedCell&gt; cells : cpFamilyMap.values()) {</span>
-<span class="source-line-no">4543</span><span id="line-4543">              miniBatchOp.addCellCount(cells.size());</span>
-<span class="source-line-no">4544</span><span id="line-4544">            }</span>
-<span class="source-line-no">4545</span><span id="line-4545">          }</span>
-<span class="source-line-no">4546</span><span id="line-4546">        }</span>
-<span class="source-line-no">4547</span><span id="line-4547">        return true;</span>
-<span class="source-line-no">4548</span><span id="line-4548">      });</span>
-<span class="source-line-no">4549</span><span id="line-4549">    }</span>
-<span class="source-line-no">4550</span><span id="line-4550"></span>
-<span class="source-line-no">4551</span><span id="line-4551">    private void mergeFamilyMaps(Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyMap,</span>
-<span class="source-line-no">4552</span><span id="line-4552">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; toBeMerged) {</span>
-<span class="source-line-no">4553</span><span id="line-4553">      for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; entry : toBeMerged.entrySet()) {</span>
-<span class="source-line-no">4554</span><span id="line-4554">        List&lt;ExtendedCell&gt; cells = familyMap.get(entry.getKey());</span>
-<span class="source-line-no">4555</span><span id="line-4555">        if (cells == null) {</span>
-<span class="source-line-no">4556</span><span id="line-4556">          familyMap.put(entry.getKey(), entry.getValue());</span>
-<span class="source-line-no">4557</span><span id="line-4557">        } else {</span>
-<span class="source-line-no">4558</span><span id="line-4558">          cells.addAll(entry.getValue());</span>
-<span class="source-line-no">4559</span><span id="line-4559">        }</span>
-<span class="source-line-no">4560</span><span id="line-4560">      }</span>
-<span class="source-line-no">4561</span><span id="line-4561">    }</span>
-<span class="source-line-no">4562</span><span id="line-4562">  }</span>
-<span class="source-line-no">4563</span><span id="line-4563"></span>
-<span class="source-line-no">4564</span><span id="line-4564">  /**</span>
-<span class="source-line-no">4565</span><span id="line-4565">   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most</span>
-<span class="source-line-no">4566</span><span id="line-4566">   * of the logic is same.</span>
-<span class="source-line-no">4567</span><span id="line-4567">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Now we will not use this operation to apply</span>
-<span class="source-line-no">4568</span><span id="line-4568">   *             edits at secondary replica side.</span>
-<span class="source-line-no">4569</span><span id="line-4569">   */</span>
-<span class="source-line-no">4570</span><span id="line-4570">  @Deprecated</span>
-<span class="source-line-no">4571</span><span id="line-4571">  private static final class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {</span>
-<span class="source-line-no">4572</span><span id="line-4572"></span>
-<span class="source-line-no">4573</span><span id="line-4573">    private long origLogSeqNum = 0;</span>
-<span class="source-line-no">4574</span><span id="line-4574"></span>
-<span class="source-line-no">4575</span><span id="line-4575">    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,</span>
-<span class="source-line-no">4576</span><span id="line-4576">      long origLogSeqNum) {</span>
-<span class="source-line-no">4577</span><span id="line-4577">      super(region, operations);</span>
-<span class="source-line-no">4578</span><span id="line-4578">      this.origLogSeqNum = origLogSeqNum;</span>
-<span class="source-line-no">4579</span><span id="line-4579">    }</span>
-<span class="source-line-no">4580</span><span id="line-4580"></span>
-<span class="source-line-no">4581</span><span id="line-4581">    @Override</span>
-<span class="source-line-no">4582</span><span id="line-4582">    public Mutation getMutation(int index) {</span>
-<span class="source-line-no">4583</span><span id="line-4583">      return this.operations[index].mutation;</span>
-<span class="source-line-no">4584</span><span id="line-4584">    }</span>
-<span class="source-line-no">4585</span><span id="line-4585"></span>
-<span class="source-line-no">4586</span><span id="line-4586">    @Override</span>
-<span class="source-line-no">4587</span><span id="line-4587">    public long getNonceGroup(int index) {</span>
-<span class="source-line-no">4588</span><span id="line-4588">      return this.operations[index].nonceGroup;</span>
-<span class="source-line-no">4589</span><span id="line-4589">    }</span>
-<span class="source-line-no">4590</span><span id="line-4590"></span>
-<span class="source-line-no">4591</span><span id="line-4591">    @Override</span>
-<span class="source-line-no">4592</span><span id="line-4592">    public long getNonce(int index) {</span>
-<span class="source-line-no">4593</span><span id="line-4593">      return this.operations[index].nonce;</span>
-<span class="source-line-no">4594</span><span id="line-4594">    }</span>
-<span class="source-line-no">4595</span><span id="line-4595"></span>
-<span class="source-line-no">4596</span><span id="line-4596">    @Override</span>
-<span class="source-line-no">4597</span><span id="line-4597">    public Mutation[] getMutationsForCoprocs() {</span>
-<span class="source-line-no">4598</span><span id="line-4598">      return null;</span>
-<span class="source-line-no">4599</span><span id="line-4599">    }</span>
+<span class="source-line-no">4513</span><span id="line-4513">      if (region.coprocessorHost != null) {</span>
+<span class="source-line-no">4514</span><span id="line-4514">        // call the coprocessor hook to do any finalization steps after the put is done</span>
+<span class="source-line-no">4515</span><span id="line-4515">        region.coprocessorHost.postBatchMutateIndispensably(</span>
+<span class="source-line-no">4516</span><span id="line-4516">          miniBatchOp != null ? miniBatchOp : createMiniBatch(size(), 0), success);</span>
+<span class="source-line-no">4517</span><span id="line-4517">      }</span>
+<span class="source-line-no">4518</span><span id="line-4518">    }</span>
+<span class="source-line-no">4519</span><span id="line-4519"></span>
+<span class="source-line-no">4520</span><span id="line-4520">    /**</span>
+<span class="source-line-no">4521</span><span id="line-4521">     * Runs prePut/preDelete/preIncrement/preAppend coprocessor hook for input mutation in a batch</span>
+<span class="source-line-no">4522</span><span id="line-4522">     * @param metrics Array of 2 ints. index 0: count of puts, index 1: count of deletes, index 2:</span>
+<span class="source-line-no">4523</span><span id="line-4523">     *                count of increments and 3: count of appends</span>
+<span class="source-line-no">4524</span><span id="line-4524">     */</span>
+<span class="source-line-no">4525</span><span id="line-4525">    private void callPreMutateCPHook(int index, final WALEdit walEdit, final int[] metrics)</span>
+<span class="source-line-no">4526</span><span id="line-4526">      throws IOException {</span>
+<span class="source-line-no">4527</span><span id="line-4527">      Mutation m = getMutation(index);</span>
+<span class="source-line-no">4528</span><span id="line-4528">      if (m instanceof Put) {</span>
+<span class="source-line-no">4529</span><span id="line-4529">        if (region.coprocessorHost.prePut((Put) m, walEdit)) {</span>
+<span class="source-line-no">4530</span><span id="line-4530">          // pre hook says skip this Put</span>
+<span class="source-line-no">4531</span><span id="line-4531">          // mark as success and skip in doMiniBatchMutation</span>
+<span class="source-line-no">4532</span><span id="line-4532">          metrics[0]++;</span>
+<span class="source-line-no">4533</span><span id="line-4533">          retCodeDetails[index] = OperationStatus.SUCCESS;</span>
+<span class="source-line-no">4534</span><span id="line-4534">        }</span>
+<span class="source-line-no">4535</span><span id="line-4535">      } else if (m instanceof Delete) {</span>
+<span class="source-line-no">4536</span><span id="line-4536">        Delete curDel = (Delete) m;</span>
+<span class="source-line-no">4537</span><span id="line-4537">        if (curDel.getFamilyCellMap().isEmpty()) {</span>
+<span class="source-line-no">4538</span><span id="line-4538">          // handle deleting a row case</span>
+<span class="source-line-no">4539</span><span id="line-4539">          // TODO: prepareDelete() has been called twice, before and after preDelete() CP hook.</span>
+<span class="source-line-no">4540</span><span id="line-4540">          // Can this be avoided?</span>
+<span class="source-line-no">4541</span><span id="line-4541">          region.prepareDelete(curDel);</span>
+<span class="source-line-no">4542</span><span id="line-4542">        }</span>
+<span class="source-line-no">4543</span><span id="line-4543">        if (region.coprocessorHost.preDelete(curDel, walEdit)) {</span>
+<span class="source-line-no">4544</span><span id="line-4544">          // pre hook says skip this Delete</span>
+<span class="source-line-no">4545</span><span id="line-4545">          // mark as success and skip in doMiniBatchMutation</span>
+<span class="source-line-no">4546</span><span id="line-4546">          metrics[1]++;</span>
+<span class="source-line-no">4547</span><span id="line-4547">          retCodeDetails[index] = OperationStatus.SUCCESS;</span>
+<span class="source-line-no">4548</span><span id="line-4548">        }</span>
+<span class="source-line-no">4549</span><span id="line-4549">      } else if (m instanceof Increment) {</span>
+<span class="source-line-no">4550</span><span id="line-4550">        Increment increment = (Increment) m;</span>
+<span class="source-line-no">4551</span><span id="line-4551">        Result result = region.coprocessorHost.preIncrement(increment, walEdit);</span>
+<span class="source-line-no">4552</span><span id="line-4552">        if (result != null) {</span>
+<span class="source-line-no">4553</span><span id="line-4553">          // pre hook says skip this Increment</span>
+<span class="source-line-no">4554</span><span id="line-4554">          // mark as success and skip in doMiniBatchMutation</span>
+<span class="source-line-no">4555</span><span id="line-4555">          metrics[2]++;</span>
+<span class="source-line-no">4556</span><span id="line-4556">          retCodeDetails[index] = new OperationStatus(OperationStatusCode.SUCCESS, result);</span>
+<span class="source-line-no">4557</span><span id="line-4557">        }</span>
+<span class="source-line-no">4558</span><span id="line-4558">      } else if (m instanceof Append) {</span>
+<span class="source-line-no">4559</span><span id="line-4559">        Append append = (Append) m;</span>
+<span class="source-line-no">4560</span><span id="line-4560">        Result result = region.coprocessorHost.preAppend(append, walEdit);</span>
+<span class="source-line-no">4561</span><span id="line-4561">        if (result != null) {</span>
+<span class="source-line-no">4562</span><span id="line-4562">          // pre hook says skip this Append</span>
+<span class="source-line-no">4563</span><span id="line-4563">          // mark as success and skip in doMiniBatchMutation</span>
+<span class="source-line-no">4564</span><span id="line-4564">          metrics[3]++;</span>
+<span class="source-line-no">4565</span><span id="line-4565">          retCodeDetails[index] = new OperationStatus(OperationStatusCode.SUCCESS, result);</span>
+<span class="source-line-no">4566</span><span id="line-4566">        }</span>
+<span class="source-line-no">4567</span><span id="line-4567">      } else {</span>
+<span class="source-line-no">4568</span><span id="line-4568">        String msg = "Put/Delete/Increment/Append mutations only supported in a batch";</span>
+<span class="source-line-no">4569</span><span id="line-4569">        retCodeDetails[index] = new OperationStatus(OperationStatusCode.FAILURE, msg);</span>
+<span class="source-line-no">4570</span><span id="line-4570">        if (isAtomic()) { // fail, atomic means all or none</span>
+<span class="source-line-no">4571</span><span id="line-4571">          throw new IOException(msg);</span>
+<span class="source-line-no">4572</span><span id="line-4572">        }</span>
+<span class="source-line-no">4573</span><span id="line-4573">      }</span>
+<span class="source-line-no">4574</span><span id="line-4574">    }</span>
+<span class="source-line-no">4575</span><span id="line-4575"></span>
+<span class="source-line-no">4576</span><span id="line-4576">    // TODO Support Increment/Append operations</span>
+<span class="source-line-no">4577</span><span id="line-4577">    private void checkAndMergeCPMutations(final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
+<span class="source-line-no">4578</span><span id="line-4578">      final List&lt;RowLock&gt; acquiredRowLocks, final long timestamp) throws IOException {</span>
+<span class="source-line-no">4579</span><span id="line-4579">      visitBatchOperations(true, nextIndexToProcess + miniBatchOp.size(), (int i) -&gt; {</span>
+<span class="source-line-no">4580</span><span id="line-4580">        // we pass (i - firstIndex) below since the call expects a relative index</span>
+<span class="source-line-no">4581</span><span id="line-4581">        Mutation[] cpMutations = miniBatchOp.getOperationsFromCoprocessors(i - nextIndexToProcess);</span>
+<span class="source-line-no">4582</span><span id="line-4582">        if (cpMutations == null) {</span>
+<span class="source-line-no">4583</span><span id="line-4583">          return true;</span>
+<span class="source-line-no">4584</span><span id="line-4584">        }</span>
+<span class="source-line-no">4585</span><span id="line-4585">        // Else Coprocessor added more Mutations corresponding to the Mutation at this index.</span>
+<span class="source-line-no">4586</span><span id="line-4586">        Mutation mutation = getMutation(i);</span>
+<span class="source-line-no">4587</span><span id="line-4587">        for (Mutation cpMutation : cpMutations) {</span>
+<span class="source-line-no">4588</span><span id="line-4588">          this.checkAndPrepareMutation(cpMutation, timestamp);</span>
+<span class="source-line-no">4589</span><span id="line-4589"></span>
+<span class="source-line-no">4590</span><span id="line-4590">          // Acquire row locks. If not, the whole batch will fail.</span>
+<span class="source-line-no">4591</span><span id="line-4591">          acquiredRowLocks.add(region.getRowLock(cpMutation.getRow(), true, null));</span>
+<span class="source-line-no">4592</span><span id="line-4592"></span>
+<span class="source-line-no">4593</span><span id="line-4593">          // Returned mutations from coprocessor correspond to the Mutation at index i. We can</span>
+<span class="source-line-no">4594</span><span id="line-4594">          // directly add the cells from those mutations to the familyMaps of this mutation.</span>
+<span class="source-line-no">4595</span><span id="line-4595">          Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; cpFamilyMap =</span>
+<span class="source-line-no">4596</span><span id="line-4596">            ClientInternalHelper.getExtendedFamilyCellMap(cpMutation);</span>
+<span class="source-line-no">4597</span><span id="line-4597">          region.rewriteCellTags(cpFamilyMap, mutation);</span>
+<span class="source-line-no">4598</span><span id="line-4598">          // will get added to the memStore later</span>
+<span class="source-line-no">4599</span><span id="line-4599">          mergeFamilyMaps(familyCellMaps[i], cpFamilyMap);</span>
 <span class="source-line-no">4600</span><span id="line-4600"></span>
-<span class="source-line-no">4601</span><span id="line-4601">    @Override</span>
-<span class="source-line-no">4602</span><span id="line-4602">    public boolean isInReplay() {</span>
-<span class="source-line-no">4603</span><span id="line-4603">      return true;</span>
-<span class="source-line-no">4604</span><span id="line-4604">    }</span>
-<span class="source-line-no">4605</span><span id="line-4605"></span>
-<span class="source-line-no">4606</span><span id="line-4606">    @Override</span>
-<span class="source-line-no">4607</span><span id="line-4607">    public long getOrigLogSeqNum() {</span>
-<span class="source-line-no">4608</span><span id="line-4608">      return this.origLogSeqNum;</span>
-<span class="source-line-no">4609</span><span id="line-4609">    }</span>
-<span class="source-line-no">4610</span><span id="line-4610"></span>
-<span class="source-line-no">4611</span><span id="line-4611">    @Override</span>
-<span class="source-line-no">4612</span><span id="line-4612">    public void startRegionOperation() throws IOException {</span>
-<span class="source-line-no">4613</span><span id="line-4613">      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);</span>
-<span class="source-line-no">4614</span><span id="line-4614">    }</span>
-<span class="source-line-no">4615</span><span id="line-4615"></span>
-<span class="source-line-no">4616</span><span id="line-4616">    @Override</span>
-<span class="source-line-no">4617</span><span id="line-4617">    public void closeRegionOperation() throws IOException {</span>
-<span class="source-line-no">4618</span><span id="line-4618">      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);</span>
-<span class="source-line-no">4619</span><span id="line-4619">    }</span>
-<span class="source-line-no">4620</span><span id="line-4620"></span>
-<span class="source-line-no">4621</span><span id="line-4621">    /**</span>
-<span class="source-line-no">4622</span><span id="line-4622">     * During replay, there could exist column families which are removed between region server</span>
-<span class="source-line-no">4623</span><span id="line-4623">     * failure and replay</span>
-<span class="source-line-no">4624</span><span id="line-4624">     */</span>
-<span class="source-line-no">4625</span><span id="line-4625">    @Override</span>
-<span class="source-line-no">4626</span><span id="line-4626">    protected void checkAndPreparePut(Put p) throws IOException {</span>
-<span class="source-line-no">4627</span><span id="line-4627">      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();</span>
-<span class="source-line-no">4628</span><span id="line-4628">      List&lt;byte[]&gt; nonExistentList = null;</span>
-<span class="source-line-no">4629</span><span id="line-4629">      for (byte[] family : familyCellMap.keySet()) {</span>
-<span class="source-line-no">4630</span><span id="line-4630">        if (!region.htableDescriptor.hasColumnFamily(family)) {</span>
-<span class="source-line-no">4631</span><span id="line-4631">          if (nonExistentList == null) {</span>
-<span class="source-line-no">4632</span><span id="line-4632">            nonExistentList = new ArrayList&lt;&gt;();</span>
-<span class="source-line-no">4633</span><span id="line-4633">          }</span>
-<span class="source-line-no">4634</span><span id="line-4634">          nonExistentList.add(family);</span>
-<span class="source-line-no">4635</span><span id="line-4635">        }</span>
-<span class="source-line-no">4636</span><span id="line-4636">      }</span>
-<span class="source-line-no">4637</span><span id="line-4637">      if (nonExistentList != null) {</span>
-<span class="source-line-no">4638</span><span id="line-4638">        for (byte[] family : nonExistentList) {</span>
-<span class="source-line-no">4639</span><span id="line-4639">          // Perhaps schema was changed between crash and replay</span>
-<span class="source-line-no">4640</span><span id="line-4640">          LOG.info("No family for {} omit from reply in region {}.", Bytes.toString(family), this);</span>
-<span class="source-line-no">4641</span><span id="line-4641">          familyCellMap.remove(family);</span>
-<span class="source-line-no">4642</span><span id="line-4642">        }</span>
-<span class="source-line-no">4643</span><span id="line-4643">      }</span>
-<span class="source-line-no">4644</span><span id="line-4644">    }</span>
-<span class="source-line-no">4645</span><span id="line-4645"></span>
-<span class="source-line-no">4646</span><span id="line-4646">    @Override</span>
-<span class="source-line-no">4647</span><span id="line-4647">    public void checkAndPrepare() throws IOException {</span>
-<span class="source-line-no">4648</span><span id="line-4648">      long now = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">4649</span><span id="line-4649">      visitBatchOperations(true, this.size(), (int index) -&gt; {</span>
-<span class="source-line-no">4650</span><span id="line-4650">        checkAndPrepareMutation(index, now);</span>
-<span class="source-line-no">4651</span><span id="line-4651">        return true;</span>
-<span class="source-line-no">4652</span><span id="line-4652">      });</span>
-<span class="source-line-no">4653</span><span id="line-4653">    }</span>
-<span class="source-line-no">4654</span><span id="line-4654"></span>
-<span class="source-line-no">4655</span><span id="line-4655">    @Override</span>
-<span class="source-line-no">4656</span><span id="line-4656">    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
-<span class="source-line-no">4657</span><span id="line-4657">      long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {</span>
-<span class="source-line-no">4658</span><span id="line-4658">      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {</span>
-<span class="source-line-no">4659</span><span id="line-4659">        // update cell count</span>
-<span class="source-line-no">4660</span><span id="line-4660">        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {</span>
-<span class="source-line-no">4661</span><span id="line-4661">          miniBatchOp.addCellCount(cells.size());</span>
-<span class="source-line-no">4662</span><span id="line-4662">        }</span>
-<span class="source-line-no">4663</span><span id="line-4663">        return true;</span>
-<span class="source-line-no">4664</span><span id="line-4664">      });</span>
-<span class="source-line-no">4665</span><span id="line-4665">    }</span>
-<span class="source-line-no">4666</span><span id="line-4666"></span>
-<span class="source-line-no">4667</span><span id="line-4667">    @Override</span>
-<span class="source-line-no">4668</span><span id="line-4668">    public WriteEntry writeMiniBatchOperationsToMemStore(</span>
-<span class="source-line-no">4669</span><span id="line-4669">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry,</span>
-<span class="source-line-no">4670</span><span id="line-4670">      long now) throws IOException {</span>
-<span class="source-line-no">4671</span><span id="line-4671">      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());</span>
-<span class="source-line-no">4672</span><span id="line-4672">      return writeEntry;</span>
-<span class="source-line-no">4673</span><span id="line-4673">    }</span>
-<span class="source-line-no">4674</span><span id="line-4674"></span>
-<span class="source-line-no">4675</span><span id="line-4675">    @Override</span>
-<span class="source-line-no">4676</span><span id="line-4676">    public void completeMiniBatchOperations(</span>
-<span class="source-line-no">4677</span><span id="line-4677">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)</span>
-<span class="source-line-no">4678</span><span id="line-4678">      throws IOException {</span>
-<span class="source-line-no">4679</span><span id="line-4679">      super.completeMiniBatchOperations(miniBatchOp, writeEntry);</span>
-<span class="source-line-no">4680</span><span id="line-4680">      region.mvcc.advanceTo(getOrigLogSeqNum());</span>
-<span class="source-line-no">4681</span><span id="line-4681">    }</span>
-<span class="source-line-no">4682</span><span id="line-4682"></span>
-<span class="source-line-no">4683</span><span id="line-4683">    @Override</span>
-<span class="source-line-no">4684</span><span id="line-4684">    protected void cacheSkipWALMutationForRegionReplication(</span>
-<span class="source-line-no">4685</span><span id="line-4685">      MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits,</span>
-<span class="source-line-no">4686</span><span id="line-4686">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
-<span class="source-line-no">4687</span><span id="line-4687">      // There is no action to do if current region is secondary replica</span>
-<span class="source-line-no">4688</span><span id="line-4688">    }</span>
-<span class="source-line-no">4689</span><span id="line-4689"></span>
-<span class="source-line-no">4690</span><span id="line-4690">  }</span>
-<span class="source-line-no">4691</span><span id="line-4691"></span>
-<span class="source-line-no">4692</span><span id="line-4692">  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,</span>
-<span class="source-line-no">4693</span><span id="line-4693">    long nonce) throws IOException {</span>
-<span class="source-line-no">4694</span><span id="line-4694">    // As it stands, this is used for 3 things</span>
-<span class="source-line-no">4695</span><span id="line-4695">    // * batchMutate with single mutation - put/delete/increment/append, separate or from</span>
-<span class="source-line-no">4696</span><span id="line-4696">    // checkAndMutate.</span>
-<span class="source-line-no">4697</span><span id="line-4697">    // * coprocessor calls (see ex. BulkDeleteEndpoint).</span>
-<span class="source-line-no">4698</span><span id="line-4698">    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...</span>
-<span class="source-line-no">4699</span><span id="line-4699">    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));</span>
-<span class="source-line-no">4700</span><span id="line-4700">  }</span>
-<span class="source-line-no">4701</span><span id="line-4701"></span>
-<span class="source-line-no">4702</span><span id="line-4702">  @Override</span>
-<span class="source-line-no">4703</span><span id="line-4703">  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {</span>
-<span class="source-line-no">4704</span><span id="line-4704">    // If the mutations has any Increment/Append operations, we need to do batchMutate atomically</span>
-<span class="source-line-no">4705</span><span id="line-4705">    boolean atomic =</span>
-<span class="source-line-no">4706</span><span id="line-4706">      Arrays.stream(mutations).anyMatch(m -&gt; m instanceof Increment || m instanceof Append);</span>
-<span class="source-line-no">4707</span><span id="line-4707">    return batchMutate(mutations, atomic);</span>
-<span class="source-line-no">4708</span><span id="line-4708">  }</span>
-<span class="source-line-no">4709</span><span id="line-4709"></span>
-<span class="source-line-no">4710</span><span id="line-4710">  OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic) throws IOException {</span>
-<span class="source-line-no">4711</span><span id="line-4711">    return TraceUtil.trace(</span>
-<span class="source-line-no">4712</span><span id="line-4712">      () -&gt; batchMutate(mutations, atomic, HConstants.NO_NONCE, HConstants.NO_NONCE),</span>
-<span class="source-line-no">4713</span><span id="line-4713">      () -&gt; createRegionSpan("Region.batchMutate"));</span>
-<span class="source-line-no">4714</span><span id="line-4714">  }</span>
-<span class="source-line-no">4715</span><span id="line-4715"></span>
-<span class="source-line-no">4716</span><span id="line-4716">  /**</span>
-<span class="source-line-no">4717</span><span id="line-4717">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Now we use</span>
-<span class="source-line-no">4718</span><span id="line-4718">   *             {@link #replayWALEntry(WALEntry, CellScanner)} for replaying edits at secondary</span>
-<span class="source-line-no">4719</span><span id="line-4719">   *             replica side.</span>
-<span class="source-line-no">4720</span><span id="line-4720">   */</span>
-<span class="source-line-no">4721</span><span id="line-4721">  @Deprecated</span>
-<span class="source-line-no">4722</span><span id="line-4722">  OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId) throws IOException {</span>
-<span class="source-line-no">4723</span><span id="line-4723">    if (</span>
-<span class="source-line-no">4724</span><span id="line-4724">      !RegionReplicaUtil.isDefaultReplica(getRegionInfo())</span>
-<span class="source-line-no">4725</span><span id="line-4725">        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId</span>
-<span class="source-line-no">4726</span><span id="line-4726">    ) {</span>
-<span class="source-line-no">4727</span><span id="line-4727">      // if it is a secondary replica we should ignore these entries silently</span>
-<span class="source-line-no">4728</span><span id="line-4728">      // since they are coming out of order</span>
-<span class="source-line-no">4729</span><span id="line-4729">      if (LOG.isTraceEnabled()) {</span>
-<span class="source-line-no">4730</span><span id="line-4730">        LOG.trace(getRegionInfo().getEncodedName() + " : " + "Skipping " + mutations.length</span>
-<span class="source-line-no">4731</span><span id="line-4731">          + " mutations with replaySeqId=" + replaySeqId</span>
-<span class="source-line-no">4732</span><span id="line-4732">          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);</span>
-<span class="source-line-no">4733</span><span id="line-4733">        for (MutationReplay mut : mutations) {</span>
-<span class="source-line-no">4734</span><span id="line-4734">          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);</span>
-<span class="source-line-no">4735</span><span id="line-4735">        }</span>
-<span class="source-line-no">4736</span><span id="line-4736">      }</span>
+<span class="source-line-no">4601</span><span id="line-4601">          // The durability of returned mutation is replaced by the corresponding mutation.</span>
+<span class="source-line-no">4602</span><span id="line-4602">          // If the corresponding mutation contains the SKIP_WAL, we shouldn't count the</span>
+<span class="source-line-no">4603</span><span id="line-4603">          // cells of returned mutation.</span>
+<span class="source-line-no">4604</span><span id="line-4604">          if (region.getEffectiveDurability(mutation.getDurability()) != Durability.SKIP_WAL) {</span>
+<span class="source-line-no">4605</span><span id="line-4605">            for (List&lt;ExtendedCell&gt; cells : cpFamilyMap.values()) {</span>
+<span class="source-line-no">4606</span><span id="line-4606">              miniBatchOp.addCellCount(cells.size());</span>
+<span class="source-line-no">4607</span><span id="line-4607">            }</span>
+<span class="source-line-no">4608</span><span id="line-4608">          }</span>
+<span class="source-line-no">4609</span><span id="line-4609">        }</span>
+<span class="source-line-no">4610</span><span id="line-4610">        return true;</span>
+<span class="source-line-no">4611</span><span id="line-4611">      });</span>
+<span class="source-line-no">4612</span><span id="line-4612">    }</span>
+<span class="source-line-no">4613</span><span id="line-4613"></span>
+<span class="source-line-no">4614</span><span id="line-4614">    private void mergeFamilyMaps(Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyMap,</span>
+<span class="source-line-no">4615</span><span id="line-4615">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; toBeMerged) {</span>
+<span class="source-line-no">4616</span><span id="line-4616">      for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; entry : toBeMerged.entrySet()) {</span>
+<span class="source-line-no">4617</span><span id="line-4617">        List&lt;ExtendedCell&gt; cells = familyMap.get(entry.getKey());</span>
+<span class="source-line-no">4618</span><span id="line-4618">        if (cells == null) {</span>
+<span class="source-line-no">4619</span><span id="line-4619">          familyMap.put(entry.getKey(), entry.getValue());</span>
+<span class="source-line-no">4620</span><span id="line-4620">        } else {</span>
+<span class="source-line-no">4621</span><span id="line-4621">          cells.addAll(entry.getValue());</span>
+<span class="source-line-no">4622</span><span id="line-4622">        }</span>
+<span class="source-line-no">4623</span><span id="line-4623">      }</span>
+<span class="source-line-no">4624</span><span id="line-4624">    }</span>
+<span class="source-line-no">4625</span><span id="line-4625">  }</span>
+<span class="source-line-no">4626</span><span id="line-4626"></span>
+<span class="source-line-no">4627</span><span id="line-4627">  /**</span>
+<span class="source-line-no">4628</span><span id="line-4628">   * Batch of mutations for replay. Base class is shared with {@link MutationBatchOperation} as most</span>
+<span class="source-line-no">4629</span><span id="line-4629">   * of the logic is same.</span>
+<span class="source-line-no">4630</span><span id="line-4630">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Now we will not use this operation to apply</span>
+<span class="source-line-no">4631</span><span id="line-4631">   *             edits at secondary replica side.</span>
+<span class="source-line-no">4632</span><span id="line-4632">   */</span>
+<span class="source-line-no">4633</span><span id="line-4633">  @Deprecated</span>
+<span class="source-line-no">4634</span><span id="line-4634">  private static final class ReplayBatchOperation extends BatchOperation&lt;MutationReplay&gt; {</span>
+<span class="source-line-no">4635</span><span id="line-4635"></span>
+<span class="source-line-no">4636</span><span id="line-4636">    private long origLogSeqNum = 0;</span>
+<span class="source-line-no">4637</span><span id="line-4637"></span>
+<span class="source-line-no">4638</span><span id="line-4638">    public ReplayBatchOperation(final HRegion region, MutationReplay[] operations,</span>
+<span class="source-line-no">4639</span><span id="line-4639">      long origLogSeqNum) {</span>
+<span class="source-line-no">4640</span><span id="line-4640">      super(region, operations);</span>
+<span class="source-line-no">4641</span><span id="line-4641">      this.origLogSeqNum = origLogSeqNum;</span>
+<span class="source-line-no">4642</span><span id="line-4642">    }</span>
+<span class="source-line-no">4643</span><span id="line-4643"></span>
+<span class="source-line-no">4644</span><span id="line-4644">    @Override</span>
+<span class="source-line-no">4645</span><span id="line-4645">    public Mutation getMutation(int index) {</span>
+<span class="source-line-no">4646</span><span id="line-4646">      return this.operations[index].mutation;</span>
+<span class="source-line-no">4647</span><span id="line-4647">    }</span>
+<span class="source-line-no">4648</span><span id="line-4648"></span>
+<span class="source-line-no">4649</span><span id="line-4649">    @Override</span>
+<span class="source-line-no">4650</span><span id="line-4650">    public long getNonceGroup(int index) {</span>
+<span class="source-line-no">4651</span><span id="line-4651">      return this.operations[index].nonceGroup;</span>
+<span class="source-line-no">4652</span><span id="line-4652">    }</span>
+<span class="source-line-no">4653</span><span id="line-4653"></span>
+<span class="source-line-no">4654</span><span id="line-4654">    @Override</span>
+<span class="source-line-no">4655</span><span id="line-4655">    public long getNonce(int index) {</span>
+<span class="source-line-no">4656</span><span id="line-4656">      return this.operations[index].nonce;</span>
+<span class="source-line-no">4657</span><span id="line-4657">    }</span>
+<span class="source-line-no">4658</span><span id="line-4658"></span>
+<span class="source-line-no">4659</span><span id="line-4659">    @Override</span>
+<span class="source-line-no">4660</span><span id="line-4660">    public Mutation[] getMutationsForCoprocs() {</span>
+<span class="source-line-no">4661</span><span id="line-4661">      return null;</span>
+<span class="source-line-no">4662</span><span id="line-4662">    }</span>
+<span class="source-line-no">4663</span><span id="line-4663"></span>
+<span class="source-line-no">4664</span><span id="line-4664">    @Override</span>
+<span class="source-line-no">4665</span><span id="line-4665">    public boolean isInReplay() {</span>
+<span class="source-line-no">4666</span><span id="line-4666">      return true;</span>
+<span class="source-line-no">4667</span><span id="line-4667">    }</span>
+<span class="source-line-no">4668</span><span id="line-4668"></span>
+<span class="source-line-no">4669</span><span id="line-4669">    @Override</span>
+<span class="source-line-no">4670</span><span id="line-4670">    public long getOrigLogSeqNum() {</span>
+<span class="source-line-no">4671</span><span id="line-4671">      return this.origLogSeqNum;</span>
+<span class="source-line-no">4672</span><span id="line-4672">    }</span>
+<span class="source-line-no">4673</span><span id="line-4673"></span>
+<span class="source-line-no">4674</span><span id="line-4674">    @Override</span>
+<span class="source-line-no">4675</span><span id="line-4675">    public void startRegionOperation() throws IOException {</span>
+<span class="source-line-no">4676</span><span id="line-4676">      region.startRegionOperation(Operation.REPLAY_BATCH_MUTATE);</span>
+<span class="source-line-no">4677</span><span id="line-4677">    }</span>
+<span class="source-line-no">4678</span><span id="line-4678"></span>
+<span class="source-line-no">4679</span><span id="line-4679">    @Override</span>
+<span class="source-line-no">4680</span><span id="line-4680">    public void closeRegionOperation() throws IOException {</span>
+<span class="source-line-no">4681</span><span id="line-4681">      region.closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);</span>
+<span class="source-line-no">4682</span><span id="line-4682">    }</span>
+<span class="source-line-no">4683</span><span id="line-4683"></span>
+<span class="source-line-no">4684</span><span id="line-4684">    /**</span>
+<span class="source-line-no">4685</span><span id="line-4685">     * During replay, there could exist column families which are removed between region server</span>
+<span class="source-line-no">4686</span><span id="line-4686">     * failure and replay</span>
+<span class="source-line-no">4687</span><span id="line-4687">     */</span>
+<span class="source-line-no">4688</span><span id="line-4688">    @Override</span>
+<span class="source-line-no">4689</span><span id="line-4689">    protected void checkAndPreparePut(Put p) throws IOException {</span>
+<span class="source-line-no">4690</span><span id="line-4690">      Map&lt;byte[], List&lt;Cell&gt;&gt; familyCellMap = p.getFamilyCellMap();</span>
+<span class="source-line-no">4691</span><span id="line-4691">      List&lt;byte[]&gt; nonExistentList = null;</span>
+<span class="source-line-no">4692</span><span id="line-4692">      for (byte[] family : familyCellMap.keySet()) {</span>
+<span class="source-line-no">4693</span><span id="line-4693">        if (!region.htableDescriptor.hasColumnFamily(family)) {</span>
+<span class="source-line-no">4694</span><span id="line-4694">          if (nonExistentList == null) {</span>
+<span class="source-line-no">4695</span><span id="line-4695">            nonExistentList = new ArrayList&lt;&gt;();</span>
+<span class="source-line-no">4696</span><span id="line-4696">          }</span>
+<span class="source-line-no">4697</span><span id="line-4697">          nonExistentList.add(family);</span>
+<span class="source-line-no">4698</span><span id="line-4698">        }</span>
+<span class="source-line-no">4699</span><span id="line-4699">      }</span>
+<span class="source-line-no">4700</span><span id="line-4700">      if (nonExistentList != null) {</span>
+<span class="source-line-no">4701</span><span id="line-4701">        for (byte[] family : nonExistentList) {</span>
+<span class="source-line-no">4702</span><span id="line-4702">          // Perhaps schema was changed between crash and replay</span>
+<span class="source-line-no">4703</span><span id="line-4703">          LOG.info("No family for {} omit from reply in region {}.", Bytes.toString(family), this);</span>
+<span class="source-line-no">4704</span><span id="line-4704">          familyCellMap.remove(family);</span>
+<span class="source-line-no">4705</span><span id="line-4705">        }</span>
+<span class="source-line-no">4706</span><span id="line-4706">      }</span>
+<span class="source-line-no">4707</span><span id="line-4707">    }</span>
+<span class="source-line-no">4708</span><span id="line-4708"></span>
+<span class="source-line-no">4709</span><span id="line-4709">    @Override</span>
+<span class="source-line-no">4710</span><span id="line-4710">    public void checkAndPrepare() throws IOException {</span>
+<span class="source-line-no">4711</span><span id="line-4711">      long now = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">4712</span><span id="line-4712">      visitBatchOperations(true, this.size(), (int index) -&gt; {</span>
+<span class="source-line-no">4713</span><span id="line-4713">        checkAndPrepareMutation(index, now);</span>
+<span class="source-line-no">4714</span><span id="line-4714">        return true;</span>
+<span class="source-line-no">4715</span><span id="line-4715">      });</span>
+<span class="source-line-no">4716</span><span id="line-4716">    }</span>
+<span class="source-line-no">4717</span><span id="line-4717"></span>
+<span class="source-line-no">4718</span><span id="line-4718">    @Override</span>
+<span class="source-line-no">4719</span><span id="line-4719">    public void prepareMiniBatchOperations(MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp,</span>
+<span class="source-line-no">4720</span><span id="line-4720">      long timestamp, final List&lt;RowLock&gt; acquiredRowLocks) throws IOException {</span>
+<span class="source-line-no">4721</span><span id="line-4721">      visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -&gt; {</span>
+<span class="source-line-no">4722</span><span id="line-4722">        // update cell count</span>
+<span class="source-line-no">4723</span><span id="line-4723">        for (List&lt;Cell&gt; cells : getMutation(index).getFamilyCellMap().values()) {</span>
+<span class="source-line-no">4724</span><span id="line-4724">          miniBatchOp.addCellCount(cells.size());</span>
+<span class="source-line-no">4725</span><span id="line-4725">        }</span>
+<span class="source-line-no">4726</span><span id="line-4726">        return true;</span>
+<span class="source-line-no">4727</span><span id="line-4727">      });</span>
+<span class="source-line-no">4728</span><span id="line-4728">    }</span>
+<span class="source-line-no">4729</span><span id="line-4729"></span>
+<span class="source-line-no">4730</span><span id="line-4730">    @Override</span>
+<span class="source-line-no">4731</span><span id="line-4731">    public WriteEntry writeMiniBatchOperationsToMemStore(</span>
+<span class="source-line-no">4732</span><span id="line-4732">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry,</span>
+<span class="source-line-no">4733</span><span id="line-4733">      long now) throws IOException {</span>
+<span class="source-line-no">4734</span><span id="line-4734">      super.writeMiniBatchOperationsToMemStore(miniBatchOp, getOrigLogSeqNum());</span>
+<span class="source-line-no">4735</span><span id="line-4735">      return writeEntry;</span>
+<span class="source-line-no">4736</span><span id="line-4736">    }</span>
 <span class="source-line-no">4737</span><span id="line-4737"></span>
-<span class="source-line-no">4738</span><span id="line-4738">      OperationStatus[] statuses = new OperationStatus[mutations.length];</span>
-<span class="source-line-no">4739</span><span id="line-4739">      for (int i = 0; i &lt; statuses.length; i++) {</span>
-<span class="source-line-no">4740</span><span id="line-4740">        statuses[i] = OperationStatus.SUCCESS;</span>
-<span class="source-line-no">4741</span><span id="line-4741">      }</span>
-<span class="source-line-no">4742</span><span id="line-4742">      return statuses;</span>
-<span class="source-line-no">4743</span><span id="line-4743">    }</span>
-<span class="source-line-no">4744</span><span id="line-4744">    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));</span>
-<span class="source-line-no">4745</span><span id="line-4745">  }</span>
-<span class="source-line-no">4746</span><span id="line-4746"></span>
-<span class="source-line-no">4747</span><span id="line-4747">  /**</span>
-<span class="source-line-no">4748</span><span id="line-4748">   * Perform a batch of mutations.</span>
-<span class="source-line-no">4749</span><span id="line-4749">   * &lt;p/&gt;</span>
-<span class="source-line-no">4750</span><span id="line-4750">   * Operations in a batch are stored with highest durability specified of for all operations in a</span>
-<span class="source-line-no">4751</span><span id="line-4751">   * batch, except for {@link Durability#SKIP_WAL}.</span>
-<span class="source-line-no">4752</span><span id="line-4752">   * &lt;p/&gt;</span>
-<span class="source-line-no">4753</span><span id="line-4753">   * This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with</span>
-<span class="source-line-no">4754</span><span id="line-4754">   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[])} with</span>
-<span class="source-line-no">4755</span><span id="line-4755">   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch and</span>
-<span class="source-line-no">4756</span><span id="line-4756">   * mutation batch is very similar, lot of code is shared by providing generic methods in base</span>
-<span class="source-line-no">4757</span><span id="line-4757">   * class {@link BatchOperation}. The logic for this method and</span>
-<span class="source-line-no">4758</span><span id="line-4758">   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which are</span>
-<span class="source-line-no">4759</span><span id="line-4759">   * overridden by derived classes to implement special behavior.</span>
-<span class="source-line-no">4760</span><span id="line-4760">   * @param batchOp contains the list of mutations</span>
-<span class="source-line-no">4761</span><span id="line-4761">   * @return an array of OperationStatus which internally contains the OperationStatusCode and the</span>
-<span class="source-line-no">4762</span><span id="line-4762">   *         exceptionMessage if any.</span>
-<span class="source-line-no">4763</span><span id="line-4763">   * @throws IOException if an IO problem is encountered</span>
-<span class="source-line-no">4764</span><span id="line-4764">   */</span>
-<span class="source-line-no">4765</span><span id="line-4765">  private OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {</span>
-<span class="source-line-no">4766</span><span id="line-4766">    boolean initialized = false;</span>
-<span class="source-line-no">4767</span><span id="line-4767">    batchOp.startRegionOperation();</span>
-<span class="source-line-no">4768</span><span id="line-4768">    try {</span>
-<span class="source-line-no">4769</span><span id="line-4769">      while (!batchOp.isDone()) {</span>
-<span class="source-line-no">4770</span><span id="line-4770">        if (!batchOp.isInReplay()) {</span>
-<span class="source-line-no">4771</span><span id="line-4771">          checkReadOnly();</span>
-<span class="source-line-no">4772</span><span id="line-4772">        }</span>
-<span class="source-line-no">4773</span><span id="line-4773">        checkResources();</span>
-<span class="source-line-no">4774</span><span id="line-4774"></span>
-<span class="source-line-no">4775</span><span id="line-4775">        if (!initialized) {</span>
-<span class="source-line-no">4776</span><span id="line-4776">          this.writeRequestsCount.add(batchOp.size());</span>
-<span class="source-line-no">4777</span><span id="line-4777">          // validate and prepare batch for write, for MutationBatchOperation it also calls CP</span>
-<span class="source-line-no">4778</span><span id="line-4778">          // prePut()/preDelete()/preIncrement()/preAppend() hooks</span>
-<span class="source-line-no">4779</span><span id="line-4779">          batchOp.checkAndPrepare();</span>
-<span class="source-line-no">4780</span><span id="line-4780">          initialized = true;</span>
-<span class="source-line-no">4781</span><span id="line-4781">        }</span>
-<span class="source-line-no">4782</span><span id="line-4782">        doMiniBatchMutate(batchOp);</span>
-<span class="source-line-no">4783</span><span id="line-4783">        requestFlushIfNeeded();</span>
-<span class="source-line-no">4784</span><span id="line-4784">      }</span>
-<span class="source-line-no">4785</span><span id="line-4785">    } finally {</span>
-<span class="source-line-no">4786</span><span id="line-4786">      if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {</span>
-<span class="source-line-no">4787</span><span id="line-4787">        rsServices.getMetrics().updateWriteQueryMeter(this, batchOp.size());</span>
-<span class="source-line-no">4788</span><span id="line-4788">      }</span>
-<span class="source-line-no">4789</span><span id="line-4789">      batchOp.closeRegionOperation();</span>
-<span class="source-line-no">4790</span><span id="line-4790">    }</span>
-<span class="source-line-no">4791</span><span id="line-4791">    return batchOp.retCodeDetails;</span>
-<span class="source-line-no">4792</span><span id="line-4792">  }</span>
-<span class="source-line-no">4793</span><span id="line-4793"></span>
-<span class="source-line-no">4794</span><span id="line-4794">  /**</span>
-<span class="source-line-no">4795</span><span id="line-4795">   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[])} In here we</span>
-<span class="source-line-no">4796</span><span id="line-4796">   * also handle replay of edits on region recover. Also gets change in size brought about by</span>
-<span class="source-line-no">4797</span><span id="line-4797">   * applying {@code batchOp}.</span>
-<span class="source-line-no">4798</span><span id="line-4798">   */</span>
-<span class="source-line-no">4799</span><span id="line-4799">  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {</span>
-<span class="source-line-no">4800</span><span id="line-4800">    boolean success = false;</span>
-<span class="source-line-no">4801</span><span id="line-4801">    WALEdit walEdit = null;</span>
-<span class="source-line-no">4802</span><span id="line-4802">    WriteEntry writeEntry = null;</span>
-<span class="source-line-no">4803</span><span id="line-4803">    boolean locked = false;</span>
-<span class="source-line-no">4804</span><span id="line-4804">    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)</span>
-<span class="source-line-no">4805</span><span id="line-4805">    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;</span>
-<span class="source-line-no">4806</span><span id="line-4806">    /** Keep track of the locks we hold so we can release them in finally clause */</span>
-<span class="source-line-no">4807</span><span id="line-4807">    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());</span>
-<span class="source-line-no">4808</span><span id="line-4808"></span>
-<span class="source-line-no">4809</span><span id="line-4809">    // Check for thread interrupt status in case we have been signaled from</span>
-<span class="source-line-no">4810</span><span id="line-4810">    // #interruptRegionOperation.</span>
-<span class="source-line-no">4811</span><span id="line-4811">    checkInterrupt();</span>
-<span class="source-line-no">4812</span><span id="line-4812"></span>
-<span class="source-line-no">4813</span><span id="line-4813">    try {</span>
-<span class="source-line-no">4814</span><span id="line-4814">      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with</span>
-<span class="source-line-no">4815</span><span id="line-4815">      // locked rows</span>
-<span class="source-line-no">4816</span><span id="line-4816">      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);</span>
-<span class="source-line-no">4817</span><span id="line-4817"></span>
-<span class="source-line-no">4818</span><span id="line-4818">      // We've now grabbed as many mutations off the list as we can</span>
-<span class="source-line-no">4819</span><span id="line-4819">      // Ensure we acquire at least one.</span>
-<span class="source-line-no">4820</span><span id="line-4820">      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {</span>
-<span class="source-line-no">4821</span><span id="line-4821">        // Nothing to put/delete/increment/append -- an exception in the above such as</span>
-<span class="source-line-no">4822</span><span id="line-4822">        // NoSuchColumnFamily?</span>
-<span class="source-line-no">4823</span><span id="line-4823">        return;</span>
-<span class="source-line-no">4824</span><span id="line-4824">      }</span>
-<span class="source-line-no">4825</span><span id="line-4825"></span>
-<span class="source-line-no">4826</span><span id="line-4826">      // Check for thread interrupt status in case we have been signaled from</span>
-<span class="source-line-no">4827</span><span id="line-4827">      // #interruptRegionOperation. Do it before we take the lock and disable interrupts for</span>
-<span class="source-line-no">4828</span><span id="line-4828">      // the WAL append.</span>
-<span class="source-line-no">4829</span><span id="line-4829">      checkInterrupt();</span>
-<span class="source-line-no">4830</span><span id="line-4830"></span>
-<span class="source-line-no">4831</span><span id="line-4831">      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());</span>
-<span class="source-line-no">4832</span><span id="line-4832">      locked = true;</span>
-<span class="source-line-no">4833</span><span id="line-4833"></span>
-<span class="source-line-no">4834</span><span id="line-4834">      // From this point until memstore update this operation should not be interrupted.</span>
-<span class="source-line-no">4835</span><span id="line-4835">      disableInterrupts();</span>
-<span class="source-line-no">4836</span><span id="line-4836"></span>
-<span class="source-line-no">4837</span><span id="line-4837">      // STEP 2. Update mini batch of all operations in progress with LATEST_TIMESTAMP timestamp</span>
-<span class="source-line-no">4838</span><span id="line-4838">      // We should record the timestamp only after we have acquired the rowLock,</span>
-<span class="source-line-no">4839</span><span id="line-4839">      // otherwise, newer puts/deletes/increment/append are not guaranteed to have a newer</span>
-<span class="source-line-no">4840</span><span id="line-4840">      // timestamp</span>
-<span class="source-line-no">4841</span><span id="line-4841"></span>
-<span class="source-line-no">4842</span><span id="line-4842">      long now = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">4843</span><span id="line-4843">      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);</span>
-<span class="source-line-no">4844</span><span id="line-4844"></span>
-<span class="source-line-no">4845</span><span id="line-4845">      // STEP 3. Build WAL edit</span>
-<span class="source-line-no">4846</span><span id="line-4846"></span>
-<span class="source-line-no">4847</span><span id="line-4847">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);</span>
-<span class="source-line-no">4848</span><span id="line-4848"></span>
-<span class="source-line-no">4849</span><span id="line-4849">      // STEP 4. Append the WALEdits to WAL and sync.</span>
-<span class="source-line-no">4850</span><span id="line-4850"></span>
-<span class="source-line-no">4851</span><span id="line-4851">      for (Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {</span>
-<span class="source-line-no">4852</span><span id="line-4852">        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();</span>
-<span class="source-line-no">4853</span><span id="line-4853">        walEdit = nonceKeyWALEditPair.getSecond();</span>
-<span class="source-line-no">4854</span><span id="line-4854">        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();</span>
-<span class="source-line-no">4855</span><span id="line-4855"></span>
-<span class="source-line-no">4856</span><span id="line-4856">        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {</span>
-<span class="source-line-no">4857</span><span id="line-4857">          writeEntry = doWALAppend(walEdit, batchOp, miniBatchOp, now, nonceKey);</span>
-<span class="source-line-no">4858</span><span id="line-4858">        }</span>
-<span class="source-line-no">4859</span><span id="line-4859"></span>
-<span class="source-line-no">4860</span><span id="line-4860">        // Complete mvcc for all but last writeEntry (for replay case)</span>
-<span class="source-line-no">4861</span><span id="line-4861">        if (it.hasNext() &amp;&amp; writeEntry != null) {</span>
-<span class="source-line-no">4862</span><span id="line-4862">          mvcc.complete(writeEntry);</span>
-<span class="source-line-no">4863</span><span id="line-4863">          writeEntry = null;</span>
-<span class="source-line-no">4864</span><span id="line-4864">        }</span>
-<span class="source-line-no">4865</span><span id="line-4865">      }</span>
-<span class="source-line-no">4866</span><span id="line-4866"></span>
-<span class="source-line-no">4867</span><span id="line-4867">      // STEP 5. Write back to memStore</span>
-<span class="source-line-no">4868</span><span id="line-4868">      // NOTE: writeEntry can be null here</span>
-<span class="source-line-no">4869</span><span id="line-4869">      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry, now);</span>
-<span class="source-line-no">4870</span><span id="line-4870"></span>
-<span class="source-line-no">4871</span><span id="line-4871">      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and</span>
-<span class="source-line-no">4872</span><span id="line-4872">      // complete mvcc for last writeEntry</span>
-<span class="source-line-no">4873</span><span id="line-4873">      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);</span>
-<span class="source-line-no">4874</span><span id="line-4874">      writeEntry = null;</span>
-<span class="source-line-no">4875</span><span id="line-4875">      success = true;</span>
-<span class="source-line-no">4876</span><span id="line-4876">    } finally {</span>
-<span class="source-line-no">4877</span><span id="line-4877">      // Call complete rather than completeAndWait because we probably had error if walKey != null</span>
-<span class="source-line-no">4878</span><span id="line-4878">      if (writeEntry != null) mvcc.complete(writeEntry);</span>
-<span class="source-line-no">4879</span><span id="line-4879"></span>
-<span class="source-line-no">4880</span><span id="line-4880">      if (locked) {</span>
-<span class="source-line-no">4881</span><span id="line-4881">        this.updatesLock.readLock().unlock();</span>
-<span class="source-line-no">4882</span><span id="line-4882">      }</span>
-<span class="source-line-no">4883</span><span id="line-4883">      releaseRowLocks(acquiredRowLocks);</span>
-<span class="source-line-no">4884</span><span id="line-4884"></span>
-<span class="source-line-no">4885</span><span id="line-4885">      enableInterrupts();</span>
-<span class="source-line-no">4886</span><span id="line-4886"></span>
-<span class="source-line-no">4887</span><span id="line-4887">      final int finalLastIndexExclusive =</span>
-<span class="source-line-no">4888</span><span id="line-4888">        miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();</span>
-<span class="source-line-no">4889</span><span id="line-4889">      final boolean finalSuccess = success;</span>
-<span class="source-line-no">4890</span><span id="line-4890">      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {</span>
-<span class="source-line-no">4891</span><span id="line-4891">        Mutation mutation = batchOp.getMutation(i);</span>
-<span class="source-line-no">4892</span><span id="line-4892">        if (mutation instanceof Increment || mutation instanceof Append) {</span>
-<span class="source-line-no">4893</span><span id="line-4893">          if (finalSuccess) {</span>
-<span class="source-line-no">4894</span><span id="line-4894">            batchOp.retCodeDetails[i] =</span>
-<span class="source-line-no">4895</span><span id="line-4895">              new OperationStatus(OperationStatusCode.SUCCESS, batchOp.results[i]);</span>
-<span class="source-line-no">4896</span><span id="line-4896">          } else {</span>
-<span class="source-line-no">4897</span><span id="line-4897">            batchOp.retCodeDetails[i] = OperationStatus.FAILURE;</span>
-<span class="source-line-no">4898</span><span id="line-4898">          }</span>
-<span class="source-line-no">4899</span><span id="line-4899">        } else {</span>
-<span class="source-line-no">4900</span><span id="line-4900">          batchOp.retCodeDetails[i] =</span>
-<span class="source-line-no">4901</span><span id="line-4901">            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;</span>
-<span class="source-line-no">4902</span><span id="line-4902">        }</span>
-<span class="source-line-no">4903</span><span id="line-4903">        return true;</span>
-<span class="source-line-no">4904</span><span id="line-4904">      });</span>
-<span class="source-line-no">4905</span><span id="line-4905"></span>
-<span class="source-line-no">4906</span><span id="line-4906">      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);</span>
+<span class="source-line-no">4738</span><span id="line-4738">    @Override</span>
+<span class="source-line-no">4739</span><span id="line-4739">    public void completeMiniBatchOperations(</span>
+<span class="source-line-no">4740</span><span id="line-4740">      final MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, final WriteEntry writeEntry)</span>
+<span class="source-line-no">4741</span><span id="line-4741">      throws IOException {</span>
+<span class="source-line-no">4742</span><span id="line-4742">      super.completeMiniBatchOperations(miniBatchOp, writeEntry);</span>
+<span class="source-line-no">4743</span><span id="line-4743">      region.mvcc.advanceTo(getOrigLogSeqNum());</span>
+<span class="source-line-no">4744</span><span id="line-4744">    }</span>
+<span class="source-line-no">4745</span><span id="line-4745"></span>
+<span class="source-line-no">4746</span><span id="line-4746">    @Override</span>
+<span class="source-line-no">4747</span><span id="line-4747">    protected void cacheSkipWALMutationForRegionReplication(</span>
+<span class="source-line-no">4748</span><span id="line-4748">      MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp, List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits,</span>
+<span class="source-line-no">4749</span><span id="line-4749">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyCellMap) {</span>
+<span class="source-line-no">4750</span><span id="line-4750">      // There is no action to do if current region is secondary replica</span>
+<span class="source-line-no">4751</span><span id="line-4751">    }</span>
+<span class="source-line-no">4752</span><span id="line-4752"></span>
+<span class="source-line-no">4753</span><span id="line-4753">  }</span>
+<span class="source-line-no">4754</span><span id="line-4754"></span>
+<span class="source-line-no">4755</span><span id="line-4755">  public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long nonceGroup,</span>
+<span class="source-line-no">4756</span><span id="line-4756">    long nonce) throws IOException {</span>
+<span class="source-line-no">4757</span><span id="line-4757">    // As it stands, this is used for 3 things</span>
+<span class="source-line-no">4758</span><span id="line-4758">    // * batchMutate with single mutation - put/delete/increment/append, separate or from</span>
+<span class="source-line-no">4759</span><span id="line-4759">    // checkAndMutate.</span>
+<span class="source-line-no">4760</span><span id="line-4760">    // * coprocessor calls (see ex. BulkDeleteEndpoint).</span>
+<span class="source-line-no">4761</span><span id="line-4761">    // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd...</span>
+<span class="source-line-no">4762</span><span id="line-4762">    return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce));</span>
+<span class="source-line-no">4763</span><span id="line-4763">  }</span>
+<span class="source-line-no">4764</span><span id="line-4764"></span>
+<span class="source-line-no">4765</span><span id="line-4765">  @Override</span>
+<span class="source-line-no">4766</span><span id="line-4766">  public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException {</span>
+<span class="source-line-no">4767</span><span id="line-4767">    // If the mutations has any Increment/Append operations, we need to do batchMutate atomically</span>
+<span class="source-line-no">4768</span><span id="line-4768">    boolean atomic =</span>
+<span class="source-line-no">4769</span><span id="line-4769">      Arrays.stream(mutations).anyMatch(m -&gt; m instanceof Increment || m instanceof Append);</span>
+<span class="source-line-no">4770</span><span id="line-4770">    return batchMutate(mutations, atomic);</span>
+<span class="source-line-no">4771</span><span id="line-4771">  }</span>
+<span class="source-line-no">4772</span><span id="line-4772"></span>
+<span class="source-line-no">4773</span><span id="line-4773">  OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic) throws IOException {</span>
+<span class="source-line-no">4774</span><span id="line-4774">    return TraceUtil.trace(</span>
+<span class="source-line-no">4775</span><span id="line-4775">      () -&gt; batchMutate(mutations, atomic, HConstants.NO_NONCE, HConstants.NO_NONCE),</span>
+<span class="source-line-no">4776</span><span id="line-4776">      () -&gt; createRegionSpan("Region.batchMutate"));</span>
+<span class="source-line-no">4777</span><span id="line-4777">  }</span>
+<span class="source-line-no">4778</span><span id="line-4778"></span>
+<span class="source-line-no">4779</span><span id="line-4779">  /**</span>
+<span class="source-line-no">4780</span><span id="line-4780">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Now we use</span>
+<span class="source-line-no">4781</span><span id="line-4781">   *             {@link #replayWALEntry(WALEntry, CellScanner)} for replaying edits at secondary</span>
+<span class="source-line-no">4782</span><span id="line-4782">   *             replica side.</span>
+<span class="source-line-no">4783</span><span id="line-4783">   */</span>
+<span class="source-line-no">4784</span><span id="line-4784">  @Deprecated</span>
+<span class="source-line-no">4785</span><span id="line-4785">  OperationStatus[] batchReplay(MutationReplay[] mutations, long replaySeqId) throws IOException {</span>
+<span class="source-line-no">4786</span><span id="line-4786">    if (</span>
+<span class="source-line-no">4787</span><span id="line-4787">      !RegionReplicaUtil.isDefaultReplica(getRegionInfo())</span>
+<span class="source-line-no">4788</span><span id="line-4788">        &amp;&amp; replaySeqId &lt; lastReplayedOpenRegionSeqId</span>
+<span class="source-line-no">4789</span><span id="line-4789">    ) {</span>
+<span class="source-line-no">4790</span><span id="line-4790">      // if it is a secondary replica we should ignore these entries silently</span>
+<span class="source-line-no">4791</span><span id="line-4791">      // since they are coming out of order</span>
+<span class="source-line-no">4792</span><span id="line-4792">      if (LOG.isTraceEnabled()) {</span>
+<span class="source-line-no">4793</span><span id="line-4793">        LOG.trace(getRegionInfo().getEncodedName() + " : " + "Skipping " + mutations.length</span>
+<span class="source-line-no">4794</span><span id="line-4794">          + " mutations with replaySeqId=" + replaySeqId</span>
+<span class="source-line-no">4795</span><span id="line-4795">          + " which is &lt; than lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);</span>
+<span class="source-line-no">4796</span><span id="line-4796">        for (MutationReplay mut : mutations) {</span>
+<span class="source-line-no">4797</span><span id="line-4797">          LOG.trace(getRegionInfo().getEncodedName() + " : Skipping : " + mut.mutation);</span>
+<span class="source-line-no">4798</span><span id="line-4798">        }</span>
+<span class="source-line-no">4799</span><span id="line-4799">      }</span>
+<span class="source-line-no">4800</span><span id="line-4800"></span>
+<span class="source-line-no">4801</span><span id="line-4801">      OperationStatus[] statuses = new OperationStatus[mutations.length];</span>
+<span class="source-line-no">4802</span><span id="line-4802">      for (int i = 0; i &lt; statuses.length; i++) {</span>
+<span class="source-line-no">4803</span><span id="line-4803">        statuses[i] = OperationStatus.SUCCESS;</span>
+<span class="source-line-no">4804</span><span id="line-4804">      }</span>
+<span class="source-line-no">4805</span><span id="line-4805">      return statuses;</span>
+<span class="source-line-no">4806</span><span id="line-4806">    }</span>
+<span class="source-line-no">4807</span><span id="line-4807">    return batchMutate(new ReplayBatchOperation(this, mutations, replaySeqId));</span>
+<span class="source-line-no">4808</span><span id="line-4808">  }</span>
+<span class="source-line-no">4809</span><span id="line-4809"></span>
+<span class="source-line-no">4810</span><span id="line-4810">  /**</span>
+<span class="source-line-no">4811</span><span id="line-4811">   * Perform a batch of mutations.</span>
+<span class="source-line-no">4812</span><span id="line-4812">   * &lt;p/&gt;</span>
+<span class="source-line-no">4813</span><span id="line-4813">   * Operations in a batch are stored with highest durability specified of for all operations in a</span>
+<span class="source-line-no">4814</span><span id="line-4814">   * batch, except for {@link Durability#SKIP_WAL}.</span>
+<span class="source-line-no">4815</span><span id="line-4815">   * &lt;p/&gt;</span>
+<span class="source-line-no">4816</span><span id="line-4816">   * This function is called from {@link #batchReplay(WALSplitUtil.MutationReplay[], long)} with</span>
+<span class="source-line-no">4817</span><span id="line-4817">   * {@link ReplayBatchOperation} instance and {@link #batchMutate(Mutation[])} with</span>
+<span class="source-line-no">4818</span><span id="line-4818">   * {@link MutationBatchOperation} instance as an argument. As the processing of replay batch and</span>
+<span class="source-line-no">4819</span><span id="line-4819">   * mutation batch is very similar, lot of code is shared by providing generic methods in base</span>
+<span class="source-line-no">4820</span><span id="line-4820">   * class {@link BatchOperation}. The logic for this method and</span>
+<span class="source-line-no">4821</span><span id="line-4821">   * {@link #doMiniBatchMutate(BatchOperation)} is implemented using methods in base class which are</span>
+<span class="source-line-no">4822</span><span id="line-4822">   * overridden by derived classes to implement special behavior.</span>
+<span class="source-line-no">4823</span><span id="line-4823">   * @param batchOp contains the list of mutations</span>
+<span class="source-line-no">4824</span><span id="line-4824">   * @return an array of OperationStatus which internally contains the OperationStatusCode and the</span>
+<span class="source-line-no">4825</span><span id="line-4825">   *         exceptionMessage if any.</span>
+<span class="source-line-no">4826</span><span id="line-4826">   * @throws IOException if an IO problem is encountered</span>
+<span class="source-line-no">4827</span><span id="line-4827">   */</span>
+<span class="source-line-no">4828</span><span id="line-4828">  private OperationStatus[] batchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {</span>
+<span class="source-line-no">4829</span><span id="line-4829">    boolean initialized = false;</span>
+<span class="source-line-no">4830</span><span id="line-4830">    batchOp.startRegionOperation();</span>
+<span class="source-line-no">4831</span><span id="line-4831">    try {</span>
+<span class="source-line-no">4832</span><span id="line-4832">      while (!batchOp.isDone()) {</span>
+<span class="source-line-no">4833</span><span id="line-4833">        if (!batchOp.isInReplay()) {</span>
+<span class="source-line-no">4834</span><span id="line-4834">          checkReadOnly();</span>
+<span class="source-line-no">4835</span><span id="line-4835">        }</span>
+<span class="source-line-no">4836</span><span id="line-4836">        checkResources();</span>
+<span class="source-line-no">4837</span><span id="line-4837"></span>
+<span class="source-line-no">4838</span><span id="line-4838">        if (!initialized) {</span>
+<span class="source-line-no">4839</span><span id="line-4839">          this.writeRequestsCount.add(batchOp.size());</span>
+<span class="source-line-no">4840</span><span id="line-4840">          // validate and prepare batch for write, for MutationBatchOperation it also calls CP</span>
+<span class="source-line-no">4841</span><span id="line-4841">          // prePut()/preDelete()/preIncrement()/preAppend() hooks</span>
+<span class="source-line-no">4842</span><span id="line-4842">          batchOp.checkAndPrepare();</span>
+<span class="source-line-no">4843</span><span id="line-4843">          initialized = true;</span>
+<span class="source-line-no">4844</span><span id="line-4844">        }</span>
+<span class="source-line-no">4845</span><span id="line-4845">        doMiniBatchMutate(batchOp);</span>
+<span class="source-line-no">4846</span><span id="line-4846">        requestFlushIfNeeded();</span>
+<span class="source-line-no">4847</span><span id="line-4847">      }</span>
+<span class="source-line-no">4848</span><span id="line-4848">    } finally {</span>
+<span class="source-line-no">4849</span><span id="line-4849">      if (rsServices != null &amp;&amp; rsServices.getMetrics() != null) {</span>
+<span class="source-line-no">4850</span><span id="line-4850">        rsServices.getMetrics().updateWriteQueryMeter(this, batchOp.size());</span>
+<span class="source-line-no">4851</span><span id="line-4851">      }</span>
+<span class="source-line-no">4852</span><span id="line-4852">      batchOp.closeRegionOperation();</span>
+<span class="source-line-no">4853</span><span id="line-4853">    }</span>
+<span class="source-line-no">4854</span><span id="line-4854">    return batchOp.retCodeDetails;</span>
+<span class="source-line-no">4855</span><span id="line-4855">  }</span>
+<span class="source-line-no">4856</span><span id="line-4856"></span>
+<span class="source-line-no">4857</span><span id="line-4857">  /**</span>
+<span class="source-line-no">4858</span><span id="line-4858">   * Called to do a piece of the batch that came in to {@link #batchMutate(Mutation[])} In here we</span>
+<span class="source-line-no">4859</span><span id="line-4859">   * also handle replay of edits on region recover. Also gets change in size brought about by</span>
+<span class="source-line-no">4860</span><span id="line-4860">   * applying {@code batchOp}.</span>
+<span class="source-line-no">4861</span><span id="line-4861">   */</span>
+<span class="source-line-no">4862</span><span id="line-4862">  private void doMiniBatchMutate(BatchOperation&lt;?&gt; batchOp) throws IOException {</span>
+<span class="source-line-no">4863</span><span id="line-4863">    boolean success = false;</span>
+<span class="source-line-no">4864</span><span id="line-4864">    WALEdit walEdit = null;</span>
+<span class="source-line-no">4865</span><span id="line-4865">    WriteEntry writeEntry = null;</span>
+<span class="source-line-no">4866</span><span id="line-4866">    boolean locked = false;</span>
+<span class="source-line-no">4867</span><span id="line-4867">    // We try to set up a batch in the range [batchOp.nextIndexToProcess,lastIndexExclusive)</span>
+<span class="source-line-no">4868</span><span id="line-4868">    MiniBatchOperationInProgress&lt;Mutation&gt; miniBatchOp = null;</span>
+<span class="source-line-no">4869</span><span id="line-4869">    /** Keep track of the locks we hold so we can release them in finally clause */</span>
+<span class="source-line-no">4870</span><span id="line-4870">    List&lt;RowLock&gt; acquiredRowLocks = Lists.newArrayListWithCapacity(batchOp.size());</span>
+<span class="source-line-no">4871</span><span id="line-4871"></span>
+<span class="source-line-no">4872</span><span id="line-4872">    // Check for thread interrupt status in case we have been signaled from</span>
+<span class="source-line-no">4873</span><span id="line-4873">    // #interruptRegionOperation.</span>
+<span class="source-line-no">4874</span><span id="line-4874">    checkInterrupt();</span>
+<span class="source-line-no">4875</span><span id="line-4875"></span>
+<span class="source-line-no">4876</span><span id="line-4876">    try {</span>
+<span class="source-line-no">4877</span><span id="line-4877">      // STEP 1. Try to acquire as many locks as we can and build mini-batch of operations with</span>
+<span class="source-line-no">4878</span><span id="line-4878">      // locked rows</span>
+<span class="source-line-no">4879</span><span id="line-4879">      miniBatchOp = batchOp.lockRowsAndBuildMiniBatch(acquiredRowLocks);</span>
+<span class="source-line-no">4880</span><span id="line-4880"></span>
+<span class="source-line-no">4881</span><span id="line-4881">      // We've now grabbed as many mutations off the list as we can</span>
+<span class="source-line-no">4882</span><span id="line-4882">      // Ensure we acquire at least one.</span>
+<span class="source-line-no">4883</span><span id="line-4883">      if (miniBatchOp.getReadyToWriteCount() &lt;= 0) {</span>
+<span class="source-line-no">4884</span><span id="line-4884">        // Nothing to put/delete/increment/append -- an exception in the above such as</span>
+<span class="source-line-no">4885</span><span id="line-4885">        // NoSuchColumnFamily?</span>
+<span class="source-line-no">4886</span><span id="line-4886">        return;</span>
+<span class="source-line-no">4887</span><span id="line-4887">      }</span>
+<span class="source-line-no">4888</span><span id="line-4888"></span>
+<span class="source-line-no">4889</span><span id="line-4889">      // Check for thread interrupt status in case we have been signaled from</span>
+<span class="source-line-no">4890</span><span id="line-4890">      // #interruptRegionOperation. Do it before we take the lock and disable interrupts for</span>
+<span class="source-line-no">4891</span><span id="line-4891">      // the WAL append.</span>
+<span class="source-line-no">4892</span><span id="line-4892">      checkInterrupt();</span>
+<span class="source-line-no">4893</span><span id="line-4893"></span>
+<span class="source-line-no">4894</span><span id="line-4894">      lock(this.updatesLock.readLock(), miniBatchOp.getReadyToWriteCount());</span>
+<span class="source-line-no">4895</span><span id="line-4895">      locked = true;</span>
+<span class="source-line-no">4896</span><span id="line-4896"></span>
+<span class="source-line-no">4897</span><span id="line-4897">      // From this point until memstore update this operation should not be interrupted.</span>
+<span class="source-line-no">4898</span><span id="line-4898">      disableInterrupts();</span>
+<span class="source-line-no">4899</span><span id="line-4899"></span>
+<span class="source-line-no">4900</span><span id="line-4900">      // STEP 2. Update mini batch of all operations in progress with LATEST_TIMESTAMP timestamp</span>
+<span class="source-line-no">4901</span><span id="line-4901">      // We should record the timestamp only after we have acquired the rowLock,</span>
+<span class="source-line-no">4902</span><span id="line-4902">      // otherwise, newer puts/deletes/increment/append are not guaranteed to have a newer</span>
+<span class="source-line-no">4903</span><span id="line-4903">      // timestamp</span>
+<span class="source-line-no">4904</span><span id="line-4904"></span>
+<span class="source-line-no">4905</span><span id="line-4905">      long now = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">4906</span><span id="line-4906">      batchOp.prepareMiniBatchOperations(miniBatchOp, now, acquiredRowLocks);</span>
 <span class="source-line-no">4907</span><span id="line-4907"></span>
-<span class="source-line-no">4908</span><span id="line-4908">      batchOp.nextIndexToProcess = finalLastIndexExclusive;</span>
-<span class="source-line-no">4909</span><span id="line-4909">    }</span>
-<span class="source-line-no">4910</span><span id="line-4910">  }</span>
+<span class="source-line-no">4908</span><span id="line-4908">      // STEP 3. Build WAL edit</span>
+<span class="source-line-no">4909</span><span id="line-4909"></span>
+<span class="source-line-no">4910</span><span id="line-4910">      List&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; walEdits = batchOp.buildWALEdits(miniBatchOp);</span>
 <span class="source-line-no">4911</span><span id="line-4911"></span>
-<span class="source-line-no">4912</span><span id="line-4912">  /**</span>
-<span class="source-line-no">4913</span><span id="line-4913">   * Returns effective durability from the passed durability and the table descriptor.</span>
-<span class="source-line-no">4914</span><span id="line-4914">   */</span>
-<span class="source-line-no">4915</span><span id="line-4915">  private Durability getEffectiveDurability(Durability d) {</span>
-<span class="source-line-no">4916</span><span id="line-4916">    return d == Durability.USE_DEFAULT ? this.regionDurability : d;</span>
-<span class="source-line-no">4917</span><span id="line-4917">  }</span>
+<span class="source-line-no">4912</span><span id="line-4912">      // STEP 4. Append the WALEdits to WAL and sync.</span>
+<span class="source-line-no">4913</span><span id="line-4913"></span>
+<span class="source-line-no">4914</span><span id="line-4914">      for (Iterator&lt;Pair&lt;NonceKey, WALEdit&gt;&gt; it = walEdits.iterator(); it.hasNext();) {</span>
+<span class="source-line-no">4915</span><span id="line-4915">        Pair&lt;NonceKey, WALEdit&gt; nonceKeyWALEditPair = it.next();</span>
+<span class="source-line-no">4916</span><span id="line-4916">        walEdit = nonceKeyWALEditPair.getSecond();</span>
+<span class="source-line-no">4917</span><span id="line-4917">        NonceKey nonceKey = nonceKeyWALEditPair.getFirst();</span>
 <span class="source-line-no">4918</span><span id="line-4918"></span>
-<span class="source-line-no">4919</span><span id="line-4919">  @Override</span>
-<span class="source-line-no">4920</span><span id="line-4920">  @Deprecated</span>
-<span class="source-line-no">4921</span><span id="line-4921">  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,</span>
-<span class="source-line-no">4922</span><span id="line-4922">    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {</span>
-<span class="source-line-no">4923</span><span id="line-4923">    CheckAndMutate checkAndMutate;</span>
-<span class="source-line-no">4924</span><span id="line-4924">    try {</span>
-<span class="source-line-no">4925</span><span id="line-4925">      CheckAndMutate.Builder builder = CheckAndMutate.newBuilder(row)</span>
-<span class="source-line-no">4926</span><span id="line-4926">        .ifMatches(family, qualifier, op, comparator.getValue()).timeRange(timeRange);</span>
-<span class="source-line-no">4927</span><span id="line-4927">      if (mutation instanceof Put) {</span>
-<span class="source-line-no">4928</span><span id="line-4928">        checkAndMutate = builder.build((Put) mutation);</span>
-<span class="source-line-no">4929</span><span id="line-4929">      } else if (mutation instanceof Delete) {</span>
-<span class="source-line-no">4930</span><span id="line-4930">        checkAndMutate = builder.build((Delete) mutation);</span>
-<span class="source-line-no">4931</span><span id="line-4931">      } else {</span>
-<span class="source-line-no">4932</span><span id="line-4932">        throw new DoNotRetryIOException(</span>
-<span class="source-line-no">4933</span><span id="line-4933">          "Unsupported mutate type: " + mutation.getClass().getSimpleName().toUpperCase());</span>
-<span class="source-line-no">4934</span><span id="line-4934">      }</span>
-<span class="source-line-no">4935</span><span id="line-4935">    } catch (IllegalArgumentException e) {</span>
-<span class="source-line-no">4936</span><span id="line-4936">      throw new DoNotRetryIOException(e.getMessage());</span>
-<span class="source-line-no">4937</span><span id="line-4937">    }</span>
-<span class="source-line-no">4938</span><span id="line-4938">    return checkAndMutate(checkAndMutate).isSuccess();</span>
-<span class="source-line-no">4939</span><span id="line-4939">  }</span>
-<span class="source-line-no">4940</span><span id="line-4940"></span>
-<span class="source-line-no">4941</span><span id="line-4941">  @Override</span>
-<span class="source-line-no">4942</span><span id="line-4942">  @Deprecated</span>
-<span class="source-line-no">4943</span><span id="line-4943">  public boolean checkAndMutate(byte[] row, Filter filter, TimeRange timeRange, Mutation mutation)</span>
-<span class="source-line-no">4944</span><span id="line-4944">    throws IOException {</span>
-<span class="source-line-no">4945</span><span id="line-4945">    CheckAndMutate checkAndMutate;</span>
-<span class="source-line-no">4946</span><span id="line-4946">    try {</span>
-<span class="source-line-no">4947</span><span id="line-4947">      CheckAndMutate.Builder builder =</span>
-<span class="source-line-no">4948</span><span id="line-4948">        CheckAndMutate.newBuilder(row).ifMatches(filter).timeRange(timeRange);</span>
-<span class="source-line-no">4949</span><span id="line-4949">      if (mutation instanceof Put) {</span>
-<span class="source-line-no">4950</span><span id="line-4950">        checkAndMutate = builder.build((Put) mutation);</span>
-<span class="source-line-no">4951</span><span id="line-4951">      } else if (mutation instanceof Delete) {</span>
-<span class="source-line-no">4952</span><span id="line-4952">        checkAndMutate = builder.build((Delete) mutation);</span>
-<span class="source-line-no">4953</span><span id="line-4953">      } else {</span>
-<span class="source-line-no">4954</span><span id="line-4954">        throw new DoNotRetryIOException(</span>
-<span class="source-line-no">4955</span><span id="line-4955">          "Unsupported mutate type: " + mutation.getClass().getSimpleName().toUpperCase());</span>
-<span class="source-line-no">4956</span><span id="line-4956">      }</span>
-<span class="source-line-no">4957</span><span id="line-4957">    } catch (IllegalArgumentException e) {</span>
-<span class="source-line-no">4958</span><span id="line-4958">      throw new DoNotRetryIOException(e.getMessage());</span>
-<span class="source-line-no">4959</span><span id="line-4959">    }</span>
-<span class="source-line-no">4960</span><span id="line-4960">    return checkAndMutate(checkAndMutate).isSuccess();</span>
-<span class="source-line-no">4961</span><span id="line-4961">  }</span>
-<span class="source-line-no">4962</span><span id="line-4962"></span>
-<span class="source-line-no">4963</span><span id="line-4963">  @Override</span>
-<span class="source-line-no">4964</span><span id="line-4964">  @Deprecated</span>
-<span class="source-line-no">4965</span><span id="line-4965">  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,</span>
-<span class="source-line-no">4966</span><span id="line-4966">    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {</span>
-<span class="source-line-no">4967</span><span id="line-4967">    CheckAndMutate checkAndMutate;</span>
-<span class="source-line-no">4968</span><span id="line-4968">    try {</span>
-<span class="source-line-no">4969</span><span id="line-4969">      checkAndMutate = CheckAndMutate.newBuilder(row)</span>
-<span class="source-line-no">4970</span><span id="line-4970">        .ifMatches(family, qualifier, op, comparator.getValue()).timeRange(timeRange).build(rm);</span>
-<span class="source-line-no">4971</span><span id="line-4971">    } catch (IllegalArgumentException e) {</span>
-<span class="source-line-no">4972</span><span id="line-4972">      throw new DoNotRetryIOException(e.getMessage());</span>
-<span class="source-line-no">4973</span><span id="line-4973">    }</span>
-<span class="source-line-no">4974</span><span id="line-4974">    return checkAndMutate(checkAndMutate).isSuccess();</span>
-<span class="source-line-no">4975</span><span id="line-4975">  }</span>
-<span class="source-line-no">4976</span><span id="line-4976"></span>
-<span class="source-line-no">4977</span><span id="line-4977">  @Override</span>
-<span class="source-line-no">4978</span><span id="line-4978">  @Deprecated</span>
-<span class="source-line-no">4979</span><span id="line-4979">  public boolean checkAndRowMutate(byte[] row, Filter filter, TimeRange timeRange, RowMutations rm)</span>
-<span class="source-line-no">4980</span><span id="line-4980">    throws IOException {</span>
-<span class="source-line-no">4981</span><span id="line-4981">    CheckAndMutate checkAndMutate;</span>
-<span class="source-line-no">4982</span><span id="line-4982">    try {</span>
-<span class="source-line-no">4983</span><span id="line-4983">      checkAndMutate =</span>
-<span class="source-line-no">4984</span><span id="line-4984">        CheckAndMutate.newBuilder(row).ifMatches(filter).timeRange(timeRange).build(rm);</span>
-<span class="source-line-no">4985</span><span id="line-4985">    } catch (IllegalArgumentException e) {</span>
-<span class="source-line-no">4986</span><span id="line-4986">      throw new DoNotRetryIOException(e.getMessage());</span>
-<span class="source-line-no">4987</span><span id="line-4987">    }</span>
-<span class="source-line-no">4988</span><span id="line-4988">    return checkAndMutate(checkAndMutate).isSuccess();</span>
-<span class="source-line-no">4989</span><span id="line-4989">  }</span>
-<span class="source-line-no">4990</span><span id="line-4990"></span>
-<span class="source-line-no">4991</span><span id="line-4991">  @Override</span>
-<span class="source-line-no">4992</span><span id="line-4992">  public CheckAndMutateResult checkAndMutate(CheckAndMutate checkAndMutate) throws IOException {</span>
-<span class="source-line-no">4993</span><span id="line-4993">    return checkAndMutate(checkAndMutate, HConstants.NO_NONCE, HConstants.NO_NONCE);</span>
-<span class="source-line-no">4994</span><span id="line-4994">  }</span>
-<span class="source-line-no">4995</span><span id="line-4995"></span>
-<span class="source-line-no">4996</span><span id="line-4996">  public CheckAndMutateResult checkAndMutate(CheckAndMutate checkAndMutate, long nonceGroup,</span>
-<span class="source-line-no">4997</span><span id="line-4997">    long nonce) throws IOException {</span>
-<span class="source-line-no">4998</span><span id="line-4998">    return TraceUtil.trace(() -&gt; checkAndMutateInternal(checkAndMutate, nonceGroup, nonce),</span>
-<span class="source-line-no">4999</span><span id="line-4999">      () -&gt; createRegionSpan("Region.checkAndMutate"));</span>
-<span class="source-line-no">5000</span><span id="line-5000">  }</span>
-<span class="source-line-no">5001</span><span id="line-5001"></span>
-<span class="source-line-no">5002</span><span id="line-5002">  private CheckAndMutateResult checkAndMutateInternal(CheckAndMutate checkAndMutate,</span>
-<span class="source-line-no">5003</span><span id="line-5003">    long nonceGroup, long nonce) throws IOException {</span>
-<span class="source-line-no">5004</span><span id="line-5004">    byte[] row = checkAndMutate.getRow();</span>
-<span class="source-line-no">5005</span><span id="line-5005">    Filter filter = null;</span>
-<span class="source-line-no">5006</span><span id="line-5006">    byte[] family = null;</span>
-<span class="source-line-no">5007</span><span id="line-5007">    byte[] qualifier = null;</span>
-<span class="source-line-no">5008</span><span id="line-5008">    CompareOperator op = null;</span>
-<span class="source-line-no">5009</span><span id="line-5009">    ByteArrayComparable comparator = null;</span>
-<span class="source-line-no">5010</span><span id="line-5010">    if (checkAndMutate.hasFilter()) {</span>
-<span class="source-line-no">5011</span><span id="line-5011">      filter = checkAndMutate.getFilter();</span>
-<span class="source-line-no">5012</span><span id="line-5012">    } else {</span>
-<span class="source-line-no">5013</span><span id="line-5013">      family = checkAndMutate.getFamily();</span>
-<span class="source-line-no">5014</span><span id="line-5014">      qualifier = checkAndMutate.getQualifier();</span>
-<span class="source-line-no">5015</span><span id="line-5015">      op = checkAndMutate.getCompareOp();</span>
-<span class="source-line-no">5016</span><span id="line-5016">      comparator = new BinaryComparator(checkAndMutate.getValue());</span>
-<span class="source-line-no">5017</span><span id="line-5017">    }</span>
-<span class="source-line-no">5018</span><span id="line-5018">    TimeRange timeRange = checkAndMutate.getTimeRange();</span>
-<span class="source-line-no">5019</span><span id="line-5019"></span>
-<span class="source-line-no">5020</span><span id="line-5020">    Mutation mutation = null;</span>
-<span class="source-line-no">5021</span><span id="line-5021">    RowMutations rowMutations = null;</span>
-<span class="source-line-no">5022</span><span id="line-5022">    if (checkAndMutate.getAction() instanceof Mutation) {</span>
-<span class="source-line-no">5023</span><span id="line-5023">      mutation = (Mutation) checkAndMutate.getAction();</span>
-<span class="source-line-no">5024</span><span id="line-5024">    } else {</span>
-<span class="source-line-no">5025</span><span id="line-5025">      rowMutations = (RowMutations) checkAndMutate.getAction();</span>
-<span class="source-line-no">5026</span><span id="line-5026">    }</span>
-<span class="source-line-no">5027</span><span id="line-5027"></span>
-<span class="source-line-no">5028</span><span id="line-5028">    if (mutation != null) {</span>
-<span class="source-line-no">5029</span><span id="line-5029">      checkMutationType(mutation);</span>
-<span class="source-line-no">5030</span><span id="line-5030">      checkRow(mutation, row);</span>
-<span class="source-line-no">5031</span><span id="line-5031">    } else {</span>
-<span class="source-line-no">5032</span><span id="line-5032">      checkRow(rowMutations, row);</span>
-<span class="source-line-no">5033</span><span id="line-5033">    }</span>
-<span class="source-line-no">5034</span><span id="line-5034">    checkReadOnly();</span>
-<span class="source-line-no">5035</span><span id="line-5035">    // TODO, add check for value length also move this check to the client</span>
-<span class="source-line-no">5036</span><span id="line-5036">    checkResources();</span>
-<span class="source-line-no">5037</span><span id="line-5037">    startRegionOperation();</span>
-<span class="source-line-no">5038</span><span id="line-5038">    try {</span>
-<span class="source-line-no">5039</span><span id="line-5039">      Get get = new Get(row);</span>
-<span class="source-line-no">5040</span><span id="line-5040">      if (family != null) {</span>
-<span class="source-line-no">5041</span><span id="line-5041">        checkFamily(family);</span>
-<span class="source-line-no">5042</span><span id="line-5042">        get.addColumn(family, qualifier);</span>
-<span class="source-line-no">5043</span><span id="line-5043">      }</span>
-<span class="source-line-no">5044</span><span id="line-5044">      if (filter != null) {</span>
-<span class="source-line-no">5045</span><span id="line-5045">        get.setFilter(filter);</span>
-<span class="source-line-no">5046</span><span id="line-5046">      }</span>
-<span class="source-line-no">5047</span><span id="line-5047">      if (timeRange != null) {</span>
-<span class="source-line-no">5048</span><span id="line-5048">        get.setTimeRange(timeRange.getMin(), timeRange.getMax());</span>
-<span class="source-line-no">5049</span><span id="line-5049">      }</span>
-<span class="source-line-no">5050</span><span id="line-5050">      // Lock row - note that doBatchMutate will relock this row if called</span>
-<span class="source-line-no">5051</span><span id="line-5051">      checkRow(row, "doCheckAndRowMutate");</span>
-<span class="source-line-no">5052</span><span id="line-5052">      RowLock rowLock = getRowLock(get.getRow(), false, null);</span>
-<span class="source-line-no">5053</span><span id="line-5053">      try {</span>
-<span class="source-line-no">5054</span><span id="line-5054">        if (this.getCoprocessorHost() != null) {</span>
-<span class="source-line-no">5055</span><span id="line-5055">          CheckAndMutateResult result =</span>
-<span class="source-line-no">5056</span><span id="line-5056">            getCoprocessorHost().preCheckAndMutateAfterRowLock(checkAndMutate);</span>
-<span class="source-line-no">5057</span><span id="line-5057">          if (result != null) {</span>
-<span class="source-line-no">5058</span><span id="line-5058">            return result;</span>
-<span class="source-line-no">5059</span><span id="line-5059">          }</span>
-<span class="source-line-no">5060</span><span id="line-5060">        }</span>
-<span class="source-line-no">5061</span><span id="line-5061"></span>
-<span class="source-line-no">5062</span><span id="line-5062">        // NOTE: We used to wait here until mvcc caught up: mvcc.await();</span>
-<span class="source-line-no">5063</span><span id="line-5063">        // Supposition is that now all changes are done under row locks, then when we go to read,</span>
-<span class="source-line-no">5064</span><span id="line-5064">        // we'll get the latest on this row.</span>
-<span class="source-line-no">5065</span><span id="line-5065">        boolean matches = false;</span>
-<span class="source-line-no">5066</span><span id="line-5066">        long cellTs = 0;</span>
-<span class="source-line-no">5067</span><span id="line-5067">        try (RegionScanner scanner = getScanner(new Scan(get))) {</span>
-<span class="source-line-no">5068</span><span id="line-5068">          // NOTE: Please don't use HRegion.get() instead,</span>
-<span class="source-line-no">5069</span><span id="line-5069">          // because it will copy cells to heap. See HBASE-26036</span>
-<span class="source-line-no">5070</span><span id="line-5070">          List&lt;ExtendedCell&gt; result = new ArrayList&lt;&gt;(1);</span>
-<span class="source-line-no">5071</span><span id="line-5071">          scanner.next(result);</span>
-<span class="source-line-no">5072</span><span id="line-5072">          if (filter != null) {</span>
-<span class="source-line-no">5073</span><span id="line-5073">            if (!result.isEmpty()) {</span>
-<span class="source-line-no">5074</span><span id="line-5074">              matches = true;</span>
-<span class="source-line-no">5075</span><span id="line-5075">              cellTs = result.get(0).getTimestamp();</span>
-<span class="source-line-no">5076</span><span id="line-5076">            }</span>
-<span class="source-line-no">5077</span><span id="line-5077">          } else {</span>
-<span class="source-line-no">5078</span><span id="line-5078">            boolean valueIsNull =</span>
-<span class="source-line-no">5079</span><span id="line-5079">              comparator.getValue() == null || comparator.getValue().length == 0;</span>
-<span class="source-line-no">5080</span><span id="line-5080">            if (result.isEmpty() &amp;&amp; valueIsNull) {</span>
-<span class="source-line-no">5081</span><span id="line-5081">              matches = op != CompareOperator.NOT_EQUAL;</span>
-<span class="source-line-no">5082</span><span id="line-5082">            } else if (result.size() &gt; 0 &amp;&amp; valueIsNull) {</span>
-<span class="source-line-no">5083</span><span id="line-5083">              matches = (result.get(0).getValueLength() == 0) == (op != CompareOperator.NOT_EQUAL);</span>
-<span class="source-line-no">5084</span><span id="line-5084">              cellTs = result.get(0).getTimestamp();</span>
-<span class="source-line-no">5085</span><span id="line-5085">            } else if (result.size() == 1) {</span>
-<span class="source-line-no">5086</span><span id="line-5086">              ExtendedCell kv = result.get(0);</span>
-<span class="source-line-no">5087</span><span id="line-5087">              cellTs = kv.getTimestamp();</span>
-<span class="source-line-no">5088</span><span id="line-5088">              int compareResult = PrivateCellUtil.compareValue(kv, comparator);</span>
-<span class="source-line-no">5089</span><span id="line-5089">              matches = matches(op, compareResult);</span>
-<span class="source-line-no">5090</span><span id="line-5090">            }</span>
-<span class="source-line-no">5091</span><span id="line-5091">          }</span>
-<span class="source-line-no">5092</span><span id="line-5092">        }</span>
-<span class="source-line-no">5093</span><span id="line-5093"></span>
-<span class="source-line-no">5094</span><span id="line-5094">        // If matches, perform the mutation or the rowMutations</span>
-<span class="source-line-no">5095</span><span id="line-5095">        if (matches) {</span>
-<span class="source-line-no">5096</span><span id="line-5096">          // We have acquired the row lock already. If the system clock is NOT monotonically</span>
-<span class="source-line-no">5097</span><span id="line-5097">          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a</span>
-<span class="source-line-no">5098</span><span id="line-5098">          // larger timestamp than what was observed via Get. doBatchMutate already does this, but</span>
-<span class="source-line-no">5099</span><span id="line-5099">          // there is no way to pass the cellTs. See HBASE-14054.</span>
-<span class="source-line-no">5100</span><span id="line-5100">          long now = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">5101</span><span id="line-5101">          long ts = Math.max(now, cellTs); // ensure write is not eclipsed</span>
-<span class="source-line-no">5102</span><span id="line-5102">          byte[] byteTs = Bytes.toBytes(ts);</span>
-<span class="source-line-no">5103</span><span id="line-5103">          if (mutation != null) {</span>
-<span class="source-line-no">5104</span><span id="line-5104">            if (mutation instanceof Put) {</span>
-<span class="source-line-no">5105</span><span id="line-5105">              updateCellTimestamps(ClientInternalHelper.getExtendedFamilyCellMap(mutation).values(),</span>
-<span class="source-line-no">5106</span><span id="line-5106">                byteTs);</span>
-<span class="source-line-no">5107</span><span id="line-5107">            }</span>
-<span class="source-line-no">5108</span><span id="line-5108">            // And else 'delete' is not needed since it already does a second get, and sets the</span>
-<span class="source-line-no">5109</span><span id="line-5109">            // timestamp from get (see prepareDeleteTimestamps).</span>
-<span class="source-line-no">5110</span><span id="line-5110">          } else {</span>
-<span class="source-line-no">5111</span><span id="line-5111">            for (Mutation m : rowMutations.getMutations()) {</span>
-<span class="source-line-no">5112</span><span id="line-5112">              if (m instanceof Put) {</span>
-<span class="source-line-no">5113</span><span id="line-5113">                updateCellTimestamps(ClientInternalHelper.getExtendedFamilyCellMap(m).values(),</span>
-<span class="source-line-no">5114</span><span id="line-5114">                  byteTs);</span>
-<span class="source-line-no">5115</span><span id="line-5115">              }</span>
-<span class="source-line-no">5116</span><span id="line-5116">            }</span>
-<span class="source-line-no">5117</span><span id="line-5117">            // And else 'delete' is not needed since it already does a second get, and sets the</span>
-<span class="source-line-no">5118</span><span id="line-5118">            // timestamp from get (see prepareDeleteTimestamps).</span>
-<span class="source-line-no">5119</span><span id="line-5119">          }</span>
-<span class="source-line-no">5120</span><span id="line-5120">          // All edits for the given row (across all column families) must happen atomically.</span>
-<span class="source-line-no">5121</span><span id="line-5121">          Result r;</span>
-<span class="source-line-no">5122</span><span id="line-5122">          if (mutation != null) {</span>
-<span class="source-line-no">5123</span><span id="line-5123">            r = mutate(mutation, true, nonceGroup, nonce).getResult();</span>
-<span class="source-line-no">5124</span><span id="line-5124">          } else {</span>
-<span class="source-line-no">5125</span><span id="line-5125">            r = mutateRow(rowMutations, nonceGroup, nonce);</span>
-<span class="source-line-no">5126</span><span id="line-5126">          }</span>
-<span class="source-line-no">5127</span><span id="line-5127">          this.checkAndMutateChecksPassed.increment();</span>
-<span class="source-line-no">5128</span><span id="line-5128">          return new CheckAndMutateResult(true, r);</span>
-<span class="source-line-no">5129</span><span id="line-5129">        }</span>
-<span class="source-line-no">5130</span><span id="line-5130">        this.checkAndMutateChecksFailed.increment();</span>
-<span class="source-line-no">5131</span><span id="line-5131">        return new CheckAndMutateResult(false, null);</span>
-<span class="source-line-no">5132</span><span id="line-5132">      } finally {</span>
-<span class="source-line-no">5133</span><span id="line-5133">        rowLock.release();</span>
-<span class="source-line-no">5134</span><span id="line-5134">      }</span>
-<span class="source-line-no">5135</span><span id="line-5135">    } finally {</span>
-<span class="source-line-no">5136</span><span id="line-5136">      closeRegionOperation();</span>
-<span class="source-line-no">5137</span><span id="line-5137">    }</span>
-<span class="source-line-no">5138</span><span id="line-5138">  }</span>
-<span class="source-line-no">5139</span><span id="line-5139"></span>
-<span class="source-line-no">5140</span><span id="line-5140">  private void checkMutationType(final Mutation mutation) throws DoNotRetryIOException {</span>
-<span class="source-line-no">5141</span><span id="line-5141">    if (</span>
-<span class="source-line-no">5142</span><span id="line-5142">      !(mutation instanceof Put) &amp;&amp; !(mutation instanceof Delete)</span>
-<span class="source-line-no">5143</span><span id="line-5143">        &amp;&amp; !(mutation instanceof Increment) &amp;&amp; !(mutation instanceof Append)</span>
-<span class="source-line-no">5144</span><span id="line-5144">    ) {</span>
-<span class="source-line-no">5145</span><span id="line-5145">      throw new org.apache.hadoop.hbase.DoNotRetryIOException(</span>
-<span class="source-line-no">5146</span><span id="line-5146">        "Action must be Put or Delete or Increment or Delete");</span>
-<span class="source-line-no">5147</span><span id="line-5147">    }</span>
-<span class="source-line-no">5148</span><span id="line-5148">  }</span>
-<span class="source-line-no">5149</span><span id="line-5149"></span>
-<span class="source-line-no">5150</span><span id="line-5150">  private void checkRow(final Row action, final byte[] row) throws DoNotRetryIOException {</span>
-<span class="source-line-no">5151</span><span id="line-5151">    if (!Bytes.equals(row, action.getRow())) {</span>
-<span class="source-line-no">5152</span><span id="line-5152">      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");</span>
-<span class="source-line-no">5153</span><span id="line-5153">    }</span>
-<span class="source-line-no">5154</span><span id="line-5154">  }</span>
-<span class="source-line-no">5155</span><span id="line-5155"></span>
-<span class="source-line-no">5156</span><span id="line-5156">  private boolean matches(final CompareOperator op, final int compareResult) {</span>
-<span class="source-line-no">5157</span><span id="line-5157">    boolean matches = false;</span>
-<span class="source-line-no">5158</span><span id="line-5158">    switch (op) {</span>
-<span class="source-line-no">5159</span><span id="line-5159">      case LESS:</span>
-<span class="source-line-no">5160</span><span id="line-5160">        matches = compareResult &lt; 0;</span>
-<span class="source-line-no">5161</span><span id="line-5161">        break;</span>
-<span class="source-line-no">5162</span><span id="line-5162">      case LESS_OR_EQUAL:</span>
-<span class="source-line-no">5163</span><span id="line-5163">        matches = compareResult &lt;= 0;</span>
-<span class="source-line-no">5164</span><span id="line-5164">        break;</span>
-<span class="source-line-no">5165</span><span id="line-5165">      case EQUAL:</span>
-<span class="source-line-no">5166</span><span id="line-5166">        matches = compareResult == 0;</span>
-<span class="source-line-no">5167</span><span id="line-5167">        break;</span>
-<span class="source-line-no">5168</span><span id="line-5168">      case NOT_EQUAL:</span>
-<span class="source-line-no">5169</span><span id="line-5169">        matches = compareResult != 0;</span>
-<span class="source-line-no">5170</span><span id="line-5170">        break;</span>
-<span class="source-line-no">5171</span><span id="line-5171">      case GREATER_OR_EQUAL:</span>
-<span class="source-line-no">5172</span><span id="line-5172">        matches = compareResult &gt;= 0;</span>
-<span class="source-line-no">5173</span><span id="line-5173">        break;</span>
-<span class="source-line-no">5174</span><span id="line-5174">      case GREATER:</span>
-<span class="source-line-no">5175</span><span id="line-5175">        matches = compareResult &gt; 0;</span>
-<span class="source-line-no">5176</span><span id="line-5176">        break;</span>
-<span class="source-line-no">5177</span><span id="line-5177">      default:</span>
-<span class="source-line-no">5178</span><span id="line-5178">        throw new RuntimeException("Unknown Compare op " + op.name());</span>
-<span class="source-line-no">5179</span><span id="line-5179">    }</span>
-<span class="source-line-no">5180</span><span id="line-5180">    return matches;</span>
-<span class="source-line-no">5181</span><span id="line-5181">  }</span>
-<span class="source-line-no">5182</span><span id="line-5182"></span>
-<span class="source-line-no">5183</span><span id="line-5183">  private OperationStatus mutate(Mutation mutation) throws IOException {</span>
-<span class="source-line-no">5184</span><span id="line-5184">    return mutate(mutation, false);</span>
-<span class="source-line-no">5185</span><span id="line-5185">  }</span>
-<span class="source-line-no">5186</span><span id="line-5186"></span>
-<span class="source-line-no">5187</span><span id="line-5187">  private OperationStatus mutate(Mutation mutation, boolean atomic) throws IOException {</span>
-<span class="source-line-no">5188</span><span id="line-5188">    return mutate(mutation, atomic, HConstants.NO_NONCE, HConstants.NO_NONCE);</span>
-<span class="source-line-no">5189</span><span id="line-5189">  }</span>
-<span class="source-line-no">5190</span><span id="line-5190"></span>
-<span class="source-line-no">5191</span><span id="line-5191">  private OperationStatus mutate(Mutation mutation, boolean atomic, long nonceGroup, long nonce)</span>
-<span class="source-line-no">5192</span><span id="line-5192">    throws IOException {</span>
-<span class="source-line-no">5193</span><span id="line-5193">    OperationStatus[] status =</span>
-<span class="source-line-no">5194</span><span id="line-5194">      this.batchMutate(new Mutation[] { mutation }, atomic, nonceGroup, nonce);</span>
-<span class="source-line-no">5195</span><span id="line-5195">    if (status[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {</span>
-<span class="source-line-no">5196</span><span id="line-5196">      throw new FailedSanityCheckException(status[0].getExceptionMsg());</span>
-<span class="source-line-no">5197</span><span id="line-5197">    } else if (status[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {</span>
-<span class="source-line-no">5198</span><span id="line-5198">      throw new NoSuchColumnFamilyException(status[0].getExceptionMsg());</span>
-<span class="source-line-no">5199</span><span id="line-5199">    } else if (status[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {</span>
-<span class="source-line-no">5200</span><span id="line-5200">      throw new RegionTooBusyException(status[0].getExceptionMsg());</span>
-<span class="source-line-no">5201</span><span id="line-5201">    }</span>
-<span class="source-line-no">5202</span><span id="line-5202">    return status[0];</span>
-<span class="source-line-no">5203</span><span id="line-5203">  }</span>
-<span class="source-line-no">5204</span><span id="line-5204"></span>
-<span class="source-line-no">5205</span><span id="line-5205">  /**</span>
-<span class="source-line-no">5206</span><span id="line-5206">   * Complete taking the snapshot on the region. Writes the region info and adds references to the</span>
-<span class="source-line-no">5207</span><span id="line-5207">   * working snapshot directory. TODO for api consistency, consider adding another version with no</span>
-<span class="source-line-no">5208</span><span id="line-5208">   * {@link ForeignExceptionSnare} arg. (In the future other cancellable HRegion methods could</span>
-<span class="source-line-no">5209</span><span id="line-5209">   * eventually add a {@link ForeignExceptionSnare}, or we could do something fancier).</span>
-<span class="source-line-no">5210</span><span id="line-5210">   * @param desc     snapshot description object</span>
-<span class="source-line-no">5211</span><span id="line-5211">   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to bail</span>
-<span class="source-line-no">5212</span><span id="line-5212">   *                 out. This is allowed to be null and will just be ignored in that case.</span>
-<span class="source-line-no">5213</span><span id="line-5213">   * @throws IOException if there is an external or internal error causing the snapshot to fail</span>
-<span class="source-line-no">5214</span><span id="line-5214">   */</span>
-<span class="source-line-no">5215</span><span id="line-5215">  public void addRegionToSnapshot(SnapshotDescription desc, ForeignExceptionSnare exnSnare)</span>
-<span class="source-line-no">5216</span><span id="line-5216">    throws IOException {</span>
-<span class="source-line-no">5217</span><span id="line-5217">    Path rootDir = CommonFSUtils.getRootDir(conf);</span>
-<span class="source-line-no">5218</span><span id="line-5218">    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);</span>
-<span class="source-line-no">5219</span><span id="line-5219"></span>
-<span class="source-line-no">5220</span><span id="line-5220">    SnapshotManifest manifest =</span>
-<span class="source-line-no">5221</span><span id="line-5221">      SnapshotManifest.create(conf, getFilesystem(), snapshotDir, desc, exnSnare);</span>
-<span class="source-line-no">5222</span><span id="line-5222">    manifest.addRegion(this);</span>
-<span class="source-line-no">5223</span><span id="line-5223">  }</span>
-<span class="source-line-no">5224</span><span id="line-5224"></span>
-<span class="source-line-no">5225</span><span id="line-5225">  private void updateSequenceId(final Iterable&lt;List&lt;ExtendedCell&gt;&gt; cellItr, final long sequenceId)</span>
-<span class="source-line-no">5226</span><span id="line-5226">    throws IOException {</span>
-<span class="source-line-no">5227</span><span id="line-5227">    for (List&lt;ExtendedCell&gt; cells : cellItr) {</span>
-<span class="source-line-no">5228</span><span id="line-5228">      if (cells == null) {</span>
-<span class="source-line-no">5229</span><span id="line-5229">        return;</span>
-<span class="source-line-no">5230</span><span id="line-5230">      }</span>
-<span class="source-line-no">5231</span><span id="line-5231">      for (ExtendedCell cell : cells) {</span>
-<span class="source-line-no">5232</span><span id="line-5232">        cell.setSequenceId(sequenceId);</span>
-<span class="source-line-no">5233</span><span id="line-5233">      }</span>
-<span class="source-line-no">5234</span><span id="line-5234">    }</span>
-<span class="source-line-no">5235</span><span id="line-5235">  }</span>
-<span class="source-line-no">5236</span><span id="line-5236"></span>
-<span class="source-line-no">5237</span><span id="line-5237">  /**</span>
-<span class="source-line-no">5238</span><span id="line-5238">   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}</span>
-<span class="source-line-no">5239</span><span id="line-5239">   * provided current timestamp.</span>
-<span class="source-line-no">5240</span><span id="line-5240">   */</span>
-<span class="source-line-no">5241</span><span id="line-5241">  private static void updateCellTimestamps(final Iterable&lt;List&lt;ExtendedCell&gt;&gt; cellItr,</span>
-<span class="source-line-no">5242</span><span id="line-5242">    final byte[] now) throws IOException {</span>
-<span class="source-line-no">5243</span><span id="line-5243">    for (List&lt;ExtendedCell&gt; cells : cellItr) {</span>
-<span class="source-line-no">5244</span><span id="line-5244">      if (cells == null) {</span>
-<span class="source-line-no">5245</span><span id="line-5245">        continue;</span>
-<span class="source-line-no">5246</span><span id="line-5246">      }</span>
-<span class="source-line-no">5247</span><span id="line-5247">      // Optimization: 'foreach' loop is not used. See:</span>
-<span class="source-line-no">5248</span><span id="line-5248">      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects</span>
-<span class="source-line-no">5249</span><span id="line-5249">      assert cells instanceof RandomAccess;</span>
-<span class="source-line-no">5250</span><span id="line-5250">      int listSize = cells.size();</span>
-<span class="source-line-no">5251</span><span id="line-5251">      for (int i = 0; i &lt; listSize; i++) {</span>
-<span class="source-line-no">5252</span><span id="line-5252">        PrivateCellUtil.updateLatestStamp(cells.get(i), now);</span>
-<span class="source-line-no">5253</span><span id="line-5253">      }</span>
-<span class="source-line-no">5254</span><span id="line-5254">    }</span>
-<span class="source-line-no">5255</span><span id="line-5255">  }</span>
-<span class="source-line-no">5256</span><span id="line-5256"></span>
-<span class="source-line-no">5257</span><span id="line-5257">  /**</span>
-<span class="source-line-no">5258</span><span id="line-5258">   * Possibly rewrite incoming cell tags.</span>
-<span class="source-line-no">5259</span><span id="line-5259">   */</span>
-<span class="source-line-no">5260</span><span id="line-5260">  private void rewriteCellTags(Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyMap, final Mutation m) {</span>
-<span class="source-line-no">5261</span><span id="line-5261">    // Check if we have any work to do and early out otherwise</span>
-<span class="source-line-no">5262</span><span id="line-5262">    // Update these checks as more logic is added here</span>
-<span class="source-line-no">5263</span><span id="line-5263">    if (m.getTTL() == Long.MAX_VALUE) {</span>
-<span class="source-line-no">5264</span><span id="line-5264">      return;</span>
-<span class="source-line-no">5265</span><span id="line-5265">    }</span>
-<span class="source-line-no">5266</span><span id="line-5266"></span>
-<span class="source-line-no">5267</span><span id="line-5267">    // From this point we know we have some work to do</span>
-<span class="source-line-no">5268</span><span id="line-5268">    for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; e : familyMap.entrySet()) {</span>
-<span class="source-line-no">5269</span><span id="line-5269">      List&lt;ExtendedCell&gt; cells = e.getValue();</span>
-<span class="source-line-no">5270</span><span id="line-5270">      assert cells instanceof RandomAccess;</span>
-<span class="source-line-no">5271</span><span id="line-5271">      int listSize = cells.size();</span>
-<span class="source-line-no">5272</span><span id="line-5272">      for (int i = 0; i &lt; listSize; i++) {</span>
-<span class="source-line-no">5273</span><span id="line-5273">        ExtendedCell cell = cells.get(i);</span>
-<span class="source-line-no">5274</span><span id="line-5274">        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);</span>
-<span class="source-line-no">5275</span><span id="line-5275">        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());</span>
-<span class="source-line-no">5276</span><span id="line-5276">        // Rewrite the cell with the updated set of tags</span>
-<span class="source-line-no">5277</span><span id="line-5277">        cells.set(i, PrivateCellUtil.createCell(cell, newTags));</span>
-<span class="source-line-no">5278</span><span id="line-5278">      }</span>
-<span class="source-line-no">5279</span><span id="line-5279">    }</span>
-<span class="source-line-no">5280</span><span id="line-5280">  }</span>
-<span class="source-line-no">5281</span><span id="line-5281"></span>
-<span class="source-line-no">5282</span><span id="line-5282">  /**</span>
-<span class="source-line-no">5283</span><span id="line-5283">   * Check if resources to support an update.</span>
-<span class="source-line-no">5284</span><span id="line-5284">   * &lt;p/&gt;</span>
-<span class="source-line-no">5285</span><span id="line-5285">   * We throw RegionTooBusyException if above memstore limit and expect client to retry using some</span>
-<span class="source-line-no">5286</span><span id="line-5286">   * kind of backoff</span>
-<span class="source-line-no">5287</span><span id="line-5287">   */</span>
-<span class="source-line-no">5288</span><span id="line-5288">  private void checkResources() throws RegionTooBusyException {</span>
-<span class="source-line-no">5289</span><span id="line-5289">    // If catalog region, do not impose resource constraints or block updates.</span>
-<span class="source-line-no">5290</span><span id="line-5290">    if (this.getRegionInfo().isMetaRegion()) {</span>
-<span class="source-line-no">5291</span><span id="line-5291">      return;</span>
-<span class="source-line-no">5292</span><span id="line-5292">    }</span>
-<span class="source-line-no">5293</span><span id="line-5293"></span>
-<span class="source-line-no">5294</span><span id="line-5294">    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();</span>
-<span class="source-line-no">5295</span><span id="line-5295">    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {</span>
-<span class="source-line-no">5296</span><span id="line-5296">      blockedRequestsCount.increment();</span>
-<span class="source-line-no">5297</span><span id="line-5297">      requestFlush();</span>
-<span class="source-line-no">5298</span><span id="line-5298">      // Don't print current limit because it will vary too much. The message is used as a key</span>
-<span class="source-line-no">5299</span><span id="line-5299">      // over in RetriesExhaustedWithDetailsException processing.</span>
-<span class="source-line-no">5300</span><span id="line-5300">      final String regionName =</span>
-<span class="source-line-no">5301</span><span id="line-5301">        this.getRegionInfo() == null ? "unknown" : this.getRegionInfo().getEncodedName();</span>
-<span class="source-line-no">5302</span><span id="line-5302">      final String serverName = this.getRegionServerServices() == null</span>
-<span class="source-line-no">5303</span><span id="line-5303">        ? "unknown"</span>
-<span class="source-line-no">5304</span><span id="line-5304">        : (this.getRegionServerServices().getServerName() == null</span>
-<span class="source-line-no">5305</span><span id="line-5305">          ? "unknown"</span>
-<span class="source-line-no">5306</span><span id="line-5306">          : this.getRegionServerServices().getServerName().toString());</span>
-<span class="source-line-no">5307</span><span id="line-5307">      RegionTooBusyException rtbe = new RegionTooBusyException("Over memstore limit="</span>
-<span class="source-line-no">5308</span><span id="line-5308">        + org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize)</span>
-<span class="source-line-no">5309</span><span id="line-5309">        + ", regionName=" + regionName + ", server=" + serverName);</span>
-<span class="source-line-no">5310</span><span id="line-5310">      LOG.warn("Region is too busy due to exceeding memstore size limit.", rtbe);</span>
-<span class="source-line-no">5311</span><span id="line-5311">      throw rtbe;</span>
-<span class="source-line-no">5312</span><span id="line-5312">    }</span>
-<span class="source-line-no">5313</span><span id="line-5313">  }</span>
-<span class="source-line-no">5314</span><span id="line-5314"></span>
-<span class="source-line-no">5315</span><span id="line-5315">  /**</span>
-<span class="source-line-no">5316</span><span id="line-5316">   * @throws IOException Throws exception if region is in read-only mode.</span>
-<span class="source-line-no">5317</span><span id="line-5317">   */</span>
-<span class="source-line-no">5318</span><span id="line-5318">  private void checkReadOnly() throws IOException {</span>
-<span class="source-line-no">5319</span><span id="line-5319">    if (isReadOnly()) {</span>
-<span class="source-line-no">5320</span><span id="line-5320">      throw new DoNotRetryIOException("region is read only");</span>
-<span class="source-line-no">5321</span><span id="line-5321">    }</span>
-<span class="source-line-no">5322</span><span id="line-5322">  }</span>
-<span class="source-line-no">5323</span><span id="line-5323"></span>
-<span class="source-line-no">5324</span><span id="line-5324">  private void checkReadsEnabled() throws IOException {</span>
-<span class="source-line-no">5325</span><span id="line-5325">    if (!this.writestate.readsEnabled) {</span>
-<span class="source-line-no">5326</span><span id="line-5326">      throw new IOException(getRegionInfo().getEncodedName()</span>
-<span class="source-line-no">5327</span><span id="line-5327">        + ": The region's reads are disabled. Cannot serve the request");</span>
+<span class="source-line-no">4919</span><span id="line-4919">        if (walEdit != null &amp;&amp; !walEdit.isEmpty()) {</span>
+<span class="source-line-no">4920</span><span id="line-4920">          writeEntry = doWALAppend(walEdit, batchOp, miniBatchOp, now, nonceKey);</span>
+<span class="source-line-no">4921</span><span id="line-4921">        }</span>
+<span class="source-line-no">4922</span><span id="line-4922"></span>
+<span class="source-line-no">4923</span><span id="line-4923">        // Complete mvcc for all but last writeEntry (for replay case)</span>
+<span class="source-line-no">4924</span><span id="line-4924">        if (it.hasNext() &amp;&amp; writeEntry != null) {</span>
+<span class="source-line-no">4925</span><span id="line-4925">          mvcc.complete(writeEntry);</span>
+<span class="source-line-no">4926</span><span id="line-4926">          writeEntry = null;</span>
+<span class="source-line-no">4927</span><span id="line-4927">        }</span>
+<span class="source-line-no">4928</span><span id="line-4928">      }</span>
+<span class="source-line-no">4929</span><span id="line-4929"></span>
+<span class="source-line-no">4930</span><span id="line-4930">      // STEP 5. Write back to memStore</span>
+<span class="source-line-no">4931</span><span id="line-4931">      // NOTE: writeEntry can be null here</span>
+<span class="source-line-no">4932</span><span id="line-4932">      writeEntry = batchOp.writeMiniBatchOperationsToMemStore(miniBatchOp, writeEntry, now);</span>
+<span class="source-line-no">4933</span><span id="line-4933"></span>
+<span class="source-line-no">4934</span><span id="line-4934">      // STEP 6. Complete MiniBatchOperations: If required calls postBatchMutate() CP hook and</span>
+<span class="source-line-no">4935</span><span id="line-4935">      // complete mvcc for last writeEntry</span>
+<span class="source-line-no">4936</span><span id="line-4936">      batchOp.completeMiniBatchOperations(miniBatchOp, writeEntry);</span>
+<span class="source-line-no">4937</span><span id="line-4937">      writeEntry = null;</span>
+<span class="source-line-no">4938</span><span id="line-4938">      success = true;</span>
+<span class="source-line-no">4939</span><span id="line-4939">    } finally {</span>
+<span class="source-line-no">4940</span><span id="line-4940">      // Call complete rather than completeAndWait because we probably had error if walKey != null</span>
+<span class="source-line-no">4941</span><span id="line-4941">      if (writeEntry != null) mvcc.complete(writeEntry);</span>
+<span class="source-line-no">4942</span><span id="line-4942"></span>
+<span class="source-line-no">4943</span><span id="line-4943">      if (locked) {</span>
+<span class="source-line-no">4944</span><span id="line-4944">        this.updatesLock.readLock().unlock();</span>
+<span class="source-line-no">4945</span><span id="line-4945">      }</span>
+<span class="source-line-no">4946</span><span id="line-4946">      releaseRowLocks(acquiredRowLocks);</span>
+<span class="source-line-no">4947</span><span id="line-4947"></span>
+<span class="source-line-no">4948</span><span id="line-4948">      enableInterrupts();</span>
+<span class="source-line-no">4949</span><span id="line-4949"></span>
+<span class="source-line-no">4950</span><span id="line-4950">      final int finalLastIndexExclusive =</span>
+<span class="source-line-no">4951</span><span id="line-4951">        miniBatchOp != null ? miniBatchOp.getLastIndexExclusive() : batchOp.size();</span>
+<span class="source-line-no">4952</span><span id="line-4952">      final boolean finalSuccess = success;</span>
+<span class="source-line-no">4953</span><span id="line-4953">      batchOp.visitBatchOperations(true, finalLastIndexExclusive, (int i) -&gt; {</span>
+<span class="source-line-no">4954</span><span id="line-4954">        Mutation mutation = batchOp.getMutation(i);</span>
+<span class="source-line-no">4955</span><span id="line-4955">        if (mutation instanceof Increment || mutation instanceof Append) {</span>
+<span class="source-line-no">4956</span><span id="line-4956">          if (finalSuccess) {</span>
+<span class="source-line-no">4957</span><span id="line-4957">            batchOp.retCodeDetails[i] =</span>
+<span class="source-line-no">4958</span><span id="line-4958">              new OperationStatus(OperationStatusCode.SUCCESS, batchOp.results[i]);</span>
+<span class="source-line-no">4959</span><span id="line-4959">          } else {</span>
+<span class="source-line-no">4960</span><span id="line-4960">            batchOp.retCodeDetails[i] = OperationStatus.FAILURE;</span>
+<span class="source-line-no">4961</span><span id="line-4961">          }</span>
+<span class="source-line-no">4962</span><span id="line-4962">        } else {</span>
+<span class="source-line-no">4963</span><span id="line-4963">          batchOp.retCodeDetails[i] =</span>
+<span class="source-line-no">4964</span><span id="line-4964">            finalSuccess ? OperationStatus.SUCCESS : OperationStatus.FAILURE;</span>
+<span class="source-line-no">4965</span><span id="line-4965">        }</span>
+<span class="source-line-no">4966</span><span id="line-4966">        return true;</span>
+<span class="source-line-no">4967</span><span id="line-4967">      });</span>
+<span class="source-line-no">4968</span><span id="line-4968"></span>
+<span class="source-line-no">4969</span><span id="line-4969">      batchOp.doPostOpCleanupForMiniBatch(miniBatchOp, walEdit, finalSuccess);</span>
+<span class="source-line-no">4970</span><span id="line-4970"></span>
+<span class="source-line-no">4971</span><span id="line-4971">      batchOp.nextIndexToProcess = finalLastIndexExclusive;</span>
+<span class="source-line-no">4972</span><span id="line-4972">    }</span>
+<span class="source-line-no">4973</span><span id="line-4973">  }</span>
+<span class="source-line-no">4974</span><span id="line-4974"></span>
+<span class="source-line-no">4975</span><span id="line-4975">  /**</span>
+<span class="source-line-no">4976</span><span id="line-4976">   * Returns effective durability from the passed durability and the table descriptor.</span>
+<span class="source-line-no">4977</span><span id="line-4977">   */</span>
+<span class="source-line-no">4978</span><span id="line-4978">  private Durability getEffectiveDurability(Durability d) {</span>
+<span class="source-line-no">4979</span><span id="line-4979">    return d == Durability.USE_DEFAULT ? this.regionDurability : d;</span>
+<span class="source-line-no">4980</span><span id="line-4980">  }</span>
+<span class="source-line-no">4981</span><span id="line-4981"></span>
+<span class="source-line-no">4982</span><span id="line-4982">  @Override</span>
+<span class="source-line-no">4983</span><span id="line-4983">  @Deprecated</span>
+<span class="source-line-no">4984</span><span id="line-4984">  public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,</span>
+<span class="source-line-no">4985</span><span id="line-4985">    ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {</span>
+<span class="source-line-no">4986</span><span id="line-4986">    CheckAndMutate checkAndMutate;</span>
+<span class="source-line-no">4987</span><span id="line-4987">    try {</span>
+<span class="source-line-no">4988</span><span id="line-4988">      CheckAndMutate.Builder builder = CheckAndMutate.newBuilder(row)</span>
+<span class="source-line-no">4989</span><span id="line-4989">        .ifMatches(family, qualifier, op, comparator.getValue()).timeRange(timeRange);</span>
+<span class="source-line-no">4990</span><span id="line-4990">      if (mutation instanceof Put) {</span>
+<span class="source-line-no">4991</span><span id="line-4991">        checkAndMutate = builder.build((Put) mutation);</span>
+<span class="source-line-no">4992</span><span id="line-4992">      } else if (mutation instanceof Delete) {</span>
+<span class="source-line-no">4993</span><span id="line-4993">        checkAndMutate = builder.build((Delete) mutation);</span>
+<span class="source-line-no">4994</span><span id="line-4994">      } else {</span>
+<span class="source-line-no">4995</span><span id="line-4995">        throw new DoNotRetryIOException(</span>
+<span class="source-line-no">4996</span><span id="line-4996">          "Unsupported mutate type: " + mutation.getClass().getSimpleName().toUpperCase());</span>
+<span class="source-line-no">4997</span><span id="line-4997">      }</span>
+<span class="source-line-no">4998</span><span id="line-4998">    } catch (IllegalArgumentException e) {</span>
+<span class="source-line-no">4999</span><span id="line-4999">      throw new DoNotRetryIOException(e.getMessage());</span>
+<span class="source-line-no">5000</span><span id="line-5000">    }</span>
+<span class="source-line-no">5001</span><span id="line-5001">    return checkAndMutate(checkAndMutate).isSuccess();</span>
+<span class="source-line-no">5002</span><span id="line-5002">  }</span>
+<span class="source-line-no">5003</span><span id="line-5003"></span>
+<span class="source-line-no">5004</span><span id="line-5004">  @Override</span>
+<span class="source-line-no">5005</span><span id="line-5005">  @Deprecated</span>
+<span class="source-line-no">5006</span><span id="line-5006">  public boolean checkAndMutate(byte[] row, Filter filter, TimeRange timeRange, Mutation mutation)</span>
+<span class="source-line-no">5007</span><span id="line-5007">    throws IOException {</span>
+<span class="source-line-no">5008</span><span id="line-5008">    CheckAndMutate checkAndMutate;</span>
+<span class="source-line-no">5009</span><span id="line-5009">    try {</span>
+<span class="source-line-no">5010</span><span id="line-5010">      CheckAndMutate.Builder builder =</span>
+<span class="source-line-no">5011</span><span id="line-5011">        CheckAndMutate.newBuilder(row).ifMatches(filter).timeRange(timeRange);</span>
+<span class="source-line-no">5012</span><span id="line-5012">      if (mutation instanceof Put) {</span>
+<span class="source-line-no">5013</span><span id="line-5013">        checkAndMutate = builder.build((Put) mutation);</span>
+<span class="source-line-no">5014</span><span id="line-5014">      } else if (mutation instanceof Delete) {</span>
+<span class="source-line-no">5015</span><span id="line-5015">        checkAndMutate = builder.build((Delete) mutation);</span>
+<span class="source-line-no">5016</span><span id="line-5016">      } else {</span>
+<span class="source-line-no">5017</span><span id="line-5017">        throw new DoNotRetryIOException(</span>
+<span class="source-line-no">5018</span><span id="line-5018">          "Unsupported mutate type: " + mutation.getClass().getSimpleName().toUpperCase());</span>
+<span class="source-line-no">5019</span><span id="line-5019">      }</span>
+<span class="source-line-no">5020</span><span id="line-5020">    } catch (IllegalArgumentException e) {</span>
+<span class="source-line-no">5021</span><span id="line-5021">      throw new DoNotRetryIOException(e.getMessage());</span>
+<span class="source-line-no">5022</span><span id="line-5022">    }</span>
+<span class="source-line-no">5023</span><span id="line-5023">    return checkAndMutate(checkAndMutate).isSuccess();</span>
+<span class="source-line-no">5024</span><span id="line-5024">  }</span>
+<span class="source-line-no">5025</span><span id="line-5025"></span>
+<span class="source-line-no">5026</span><span id="line-5026">  @Override</span>
+<span class="source-line-no">5027</span><span id="line-5027">  @Deprecated</span>
+<span class="source-line-no">5028</span><span id="line-5028">  public boolean checkAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,</span>
+<span class="source-line-no">5029</span><span id="line-5029">    ByteArrayComparable comparator, TimeRange timeRange, RowMutations rm) throws IOException {</span>
+<span class="source-line-no">5030</span><span id="line-5030">    CheckAndMutate checkAndMutate;</span>
+<span class="source-line-no">5031</span><span id="line-5031">    try {</span>
+<span class="source-line-no">5032</span><span id="line-5032">      checkAndMutate = CheckAndMutate.newBuilder(row)</span>
+<span class="source-line-no">5033</span><span id="line-5033">        .ifMatches(family, qualifier, op, comparator.getValue()).timeRange(timeRange).build(rm);</span>
+<span class="source-line-no">5034</span><span id="line-5034">    } catch (IllegalArgumentException e) {</span>
+<span class="source-line-no">5035</span><span id="line-5035">      throw new DoNotRetryIOException(e.getMessage());</span>
+<span class="source-line-no">5036</span><span id="line-5036">    }</span>
+<span class="source-line-no">5037</span><span id="line-5037">    return checkAndMutate(checkAndMutate).isSuccess();</span>
+<span class="source-line-no">5038</span><span id="line-5038">  }</span>
+<span class="source-line-no">5039</span><span id="line-5039"></span>
+<span class="source-line-no">5040</span><span id="line-5040">  @Override</span>
+<span class="source-line-no">5041</span><span id="line-5041">  @Deprecated</span>
+<span class="source-line-no">5042</span><span id="line-5042">  public boolean checkAndRowMutate(byte[] row, Filter filter, TimeRange timeRange, RowMutations rm)</span>
+<span class="source-line-no">5043</span><span id="line-5043">    throws IOException {</span>
+<span class="source-line-no">5044</span><span id="line-5044">    CheckAndMutate checkAndMutate;</span>
+<span class="source-line-no">5045</span><span id="line-5045">    try {</span>
+<span class="source-line-no">5046</span><span id="line-5046">      checkAndMutate =</span>
+<span class="source-line-no">5047</span><span id="line-5047">        CheckAndMutate.newBuilder(row).ifMatches(filter).timeRange(timeRange).build(rm);</span>
+<span class="source-line-no">5048</span><span id="line-5048">    } catch (IllegalArgumentException e) {</span>
+<span class="source-line-no">5049</span><span id="line-5049">      throw new DoNotRetryIOException(e.getMessage());</span>
+<span class="source-line-no">5050</span><span id="line-5050">    }</span>
+<span class="source-line-no">5051</span><span id="line-5051">    return checkAndMutate(checkAndMutate).isSuccess();</span>
+<span class="source-line-no">5052</span><span id="line-5052">  }</span>
+<span class="source-line-no">5053</span><span id="line-5053"></span>
+<span class="source-line-no">5054</span><span id="line-5054">  @Override</span>
+<span class="source-line-no">5055</span><span id="line-5055">  public CheckAndMutateResult checkAndMutate(CheckAndMutate checkAndMutate) throws IOException {</span>
+<span class="source-line-no">5056</span><span id="line-5056">    return checkAndMutate(checkAndMutate, HConstants.NO_NONCE, HConstants.NO_NONCE);</span>
+<span class="source-line-no">5057</span><span id="line-5057">  }</span>
+<span class="source-line-no">5058</span><span id="line-5058"></span>
+<span class="source-line-no">5059</span><span id="line-5059">  public CheckAndMutateResult checkAndMutate(CheckAndMutate checkAndMutate, long nonceGroup,</span>
+<span class="source-line-no">5060</span><span id="line-5060">    long nonce) throws IOException {</span>
+<span class="source-line-no">5061</span><span id="line-5061">    return TraceUtil.trace(() -&gt; checkAndMutateInternal(checkAndMutate, nonceGroup, nonce),</span>
+<span class="source-line-no">5062</span><span id="line-5062">      () -&gt; createRegionSpan("Region.checkAndMutate"));</span>
+<span class="source-line-no">5063</span><span id="line-5063">  }</span>
+<span class="source-line-no">5064</span><span id="line-5064"></span>
+<span class="source-line-no">5065</span><span id="line-5065">  private CheckAndMutateResult checkAndMutateInternal(CheckAndMutate checkAndMutate,</span>
+<span class="source-line-no">5066</span><span id="line-5066">    long nonceGroup, long nonce) throws IOException {</span>
+<span class="source-line-no">5067</span><span id="line-5067">    byte[] row = checkAndMutate.getRow();</span>
+<span class="source-line-no">5068</span><span id="line-5068">    Filter filter = null;</span>
+<span class="source-line-no">5069</span><span id="line-5069">    byte[] family = null;</span>
+<span class="source-line-no">5070</span><span id="line-5070">    byte[] qualifier = null;</span>
+<span class="source-line-no">5071</span><span id="line-5071">    CompareOperator op = null;</span>
+<span class="source-line-no">5072</span><span id="line-5072">    ByteArrayComparable comparator = null;</span>
+<span class="source-line-no">5073</span><span id="line-5073">    if (checkAndMutate.hasFilter()) {</span>
+<span class="source-line-no">5074</span><span id="line-5074">      filter = checkAndMutate.getFilter();</span>
+<span class="source-line-no">5075</span><span id="line-5075">    } else {</span>
+<span class="source-line-no">5076</span><span id="line-5076">      family = checkAndMutate.getFamily();</span>
+<span class="source-line-no">5077</span><span id="line-5077">      qualifier = checkAndMutate.getQualifier();</span>
+<span class="source-line-no">5078</span><span id="line-5078">      op = checkAndMutate.getCompareOp();</span>
+<span class="source-line-no">5079</span><span id="line-5079">      comparator = new BinaryComparator(checkAndMutate.getValue());</span>
+<span class="source-line-no">5080</span><span id="line-5080">    }</span>
+<span class="source-line-no">5081</span><span id="line-5081">    TimeRange timeRange = checkAndMutate.getTimeRange();</span>
+<span class="source-line-no">5082</span><span id="line-5082"></span>
+<span class="source-line-no">5083</span><span id="line-5083">    Mutation mutation = null;</span>
+<span class="source-line-no">5084</span><span id="line-5084">    RowMutations rowMutations = null;</span>
+<span class="source-line-no">5085</span><span id="line-5085">    if (checkAndMutate.getAction() instanceof Mutation) {</span>
+<span class="source-line-no">5086</span><span id="line-5086">      mutation = (Mutation) checkAndMutate.getAction();</span>
+<span class="source-line-no">5087</span><span id="line-5087">    } else {</span>
+<span class="source-line-no">5088</span><span id="line-5088">      rowMutations = (RowMutations) checkAndMutate.getAction();</span>
+<span class="source-line-no">5089</span><span id="line-5089">    }</span>
+<span class="source-line-no">5090</span><span id="line-5090"></span>
+<span class="source-line-no">5091</span><span id="line-5091">    if (mutation != null) {</span>
+<span class="source-line-no">5092</span><span id="line-5092">      checkMutationType(mutation);</span>
+<span class="source-line-no">5093</span><span id="line-5093">      checkRow(mutation, row);</span>
+<span class="source-line-no">5094</span><span id="line-5094">    } else {</span>
+<span class="source-line-no">5095</span><span id="line-5095">      checkRow(rowMutations, row);</span>
+<span class="source-line-no">5096</span><span id="line-5096">    }</span>
+<span class="source-line-no">5097</span><span id="line-5097">    checkReadOnly();</span>
+<span class="source-line-no">5098</span><span id="line-5098">    // TODO, add check for value length also move this check to the client</span>
+<span class="source-line-no">5099</span><span id="line-5099">    checkResources();</span>
+<span class="source-line-no">5100</span><span id="line-5100">    startRegionOperation();</span>
+<span class="source-line-no">5101</span><span id="line-5101">    try {</span>
+<span class="source-line-no">5102</span><span id="line-5102">      Get get = new Get(row);</span>
+<span class="source-line-no">5103</span><span id="line-5103">      if (family != null) {</span>
+<span class="source-line-no">5104</span><span id="line-5104">        checkFamily(family);</span>
+<span class="source-line-no">5105</span><span id="line-5105">        get.addColumn(family, qualifier);</span>
+<span class="source-line-no">5106</span><span id="line-5106">      }</span>
+<span class="source-line-no">5107</span><span id="line-5107">      if (filter != null) {</span>
+<span class="source-line-no">5108</span><span id="line-5108">        get.setFilter(filter);</span>
+<span class="source-line-no">5109</span><span id="line-5109">      }</span>
+<span class="source-line-no">5110</span><span id="line-5110">      if (timeRange != null) {</span>
+<span class="source-line-no">5111</span><span id="line-5111">        get.setTimeRange(timeRange.getMin(), timeRange.getMax());</span>
+<span class="source-line-no">5112</span><span id="line-5112">      }</span>
+<span class="source-line-no">5113</span><span id="line-5113">      // Lock row - note that doBatchMutate will relock this row if called</span>
+<span class="source-line-no">5114</span><span id="line-5114">      checkRow(row, "doCheckAndRowMutate");</span>
+<span class="source-line-no">5115</span><span id="line-5115">      RowLock rowLock = getRowLock(get.getRow(), false, null);</span>
+<span class="source-line-no">5116</span><span id="line-5116">      try {</span>
+<span class="source-line-no">5117</span><span id="line-5117">        if (this.getCoprocessorHost() != null) {</span>
+<span class="source-line-no">5118</span><span id="line-5118">          CheckAndMutateResult result =</span>
+<span class="source-line-no">5119</span><span id="line-5119">            getCoprocessorHost().preCheckAndMutateAfterRowLock(checkAndMutate);</span>
+<span class="source-line-no">5120</span><span id="line-5120">          if (result != null) {</span>
+<span class="source-line-no">5121</span><span id="line-5121">            return result;</span>
+<span class="source-line-no">5122</span><span id="line-5122">          }</span>
+<span class="source-line-no">5123</span><span id="line-5123">        }</span>
+<span class="source-line-no">5124</span><span id="line-5124"></span>
+<span class="source-line-no">5125</span><span id="line-5125">        // NOTE: We used to wait here until mvcc caught up: mvcc.await();</span>
+<span class="source-line-no">5126</span><span id="line-5126">        // Supposition is that now all changes are done under row locks, then when we go to read,</span>
+<span class="source-line-no">5127</span><span id="line-5127">        // we'll get the latest on this row.</span>
+<span class="source-line-no">5128</span><span id="line-5128">        boolean matches = false;</span>
+<span class="source-line-no">5129</span><span id="line-5129">        long cellTs = 0;</span>
+<span class="source-line-no">5130</span><span id="line-5130">        try (RegionScanner scanner = getScanner(new Scan(get))) {</span>
+<span class="source-line-no">5131</span><span id="line-5131">          // NOTE: Please don't use HRegion.get() instead,</span>
+<span class="source-line-no">5132</span><span id="line-5132">          // because it will copy cells to heap. See HBASE-26036</span>
+<span class="source-line-no">5133</span><span id="line-5133">          List&lt;ExtendedCell&gt; result = new ArrayList&lt;&gt;(1);</span>
+<span class="source-line-no">5134</span><span id="line-5134">          scanner.next(result);</span>
+<span class="source-line-no">5135</span><span id="line-5135">          if (filter != null) {</span>
+<span class="source-line-no">5136</span><span id="line-5136">            if (!result.isEmpty()) {</span>
+<span class="source-line-no">5137</span><span id="line-5137">              matches = true;</span>
+<span class="source-line-no">5138</span><span id="line-5138">              cellTs = result.get(0).getTimestamp();</span>
+<span class="source-line-no">5139</span><span id="line-5139">            }</span>
+<span class="source-line-no">5140</span><span id="line-5140">          } else {</span>
+<span class="source-line-no">5141</span><span id="line-5141">            boolean valueIsNull =</span>
+<span class="source-line-no">5142</span><span id="line-5142">              comparator.getValue() == null || comparator.getValue().length == 0;</span>
+<span class="source-line-no">5143</span><span id="line-5143">            if (result.isEmpty() &amp;&amp; valueIsNull) {</span>
+<span class="source-line-no">5144</span><span id="line-5144">              matches = op != CompareOperator.NOT_EQUAL;</span>
+<span class="source-line-no">5145</span><span id="line-5145">            } else if (result.size() &gt; 0 &amp;&amp; valueIsNull) {</span>
+<span class="source-line-no">5146</span><span id="line-5146">              matches = (result.get(0).getValueLength() == 0) == (op != CompareOperator.NOT_EQUAL);</span>
+<span class="source-line-no">5147</span><span id="line-5147">              cellTs = result.get(0).getTimestamp();</span>
+<span class="source-line-no">5148</span><span id="line-5148">            } else if (result.size() == 1) {</span>
+<span class="source-line-no">5149</span><span id="line-5149">              ExtendedCell kv = result.get(0);</span>
+<span class="source-line-no">5150</span><span id="line-5150">              cellTs = kv.getTimestamp();</span>
+<span class="source-line-no">5151</span><span id="line-5151">              int compareResult = PrivateCellUtil.compareValue(kv, comparator);</span>
+<span class="source-line-no">5152</span><span id="line-5152">              matches = matches(op, compareResult);</span>
+<span class="source-line-no">5153</span><span id="line-5153">            }</span>
+<span class="source-line-no">5154</span><span id="line-5154">          }</span>
+<span class="source-line-no">5155</span><span id="line-5155">        }</span>
+<span class="source-line-no">5156</span><span id="line-5156"></span>
+<span class="source-line-no">5157</span><span id="line-5157">        // If matches, perform the mutation or the rowMutations</span>
+<span class="source-line-no">5158</span><span id="line-5158">        if (matches) {</span>
+<span class="source-line-no">5159</span><span id="line-5159">          // We have acquired the row lock already. If the system clock is NOT monotonically</span>
+<span class="source-line-no">5160</span><span id="line-5160">          // non-decreasing (see HBASE-14070) we should make sure that the mutation has a</span>
+<span class="source-line-no">5161</span><span id="line-5161">          // larger timestamp than what was observed via Get. doBatchMutate already does this, but</span>
+<span class="source-line-no">5162</span><span id="line-5162">          // there is no way to pass the cellTs. See HBASE-14054.</span>
+<span class="source-line-no">5163</span><span id="line-5163">          long now = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">5164</span><span id="line-5164">          long ts = Math.max(now, cellTs); // ensure write is not eclipsed</span>
+<span class="source-line-no">5165</span><span id="line-5165">          byte[] byteTs = Bytes.toBytes(ts);</span>
+<span class="source-line-no">5166</span><span id="line-5166">          if (mutation != null) {</span>
+<span class="source-line-no">5167</span><span id="line-5167">            if (mutation instanceof Put) {</span>
+<span class="source-line-no">5168</span><span id="line-5168">              updateCellTimestamps(ClientInternalHelper.getExtendedFamilyCellMap(mutation).values(),</span>
+<span class="source-line-no">5169</span><span id="line-5169">                byteTs);</span>
+<span class="source-line-no">5170</span><span id="line-5170">            }</span>
+<span class="source-line-no">5171</span><span id="line-5171">            // And else 'delete' is not needed since it already does a second get, and sets the</span>
+<span class="source-line-no">5172</span><span id="line-5172">            // timestamp from get (see prepareDeleteTimestamps).</span>
+<span class="source-line-no">5173</span><span id="line-5173">          } else {</span>
+<span class="source-line-no">5174</span><span id="line-5174">            for (Mutation m : rowMutations.getMutations()) {</span>
+<span class="source-line-no">5175</span><span id="line-5175">              if (m instanceof Put) {</span>
+<span class="source-line-no">5176</span><span id="line-5176">                updateCellTimestamps(ClientInternalHelper.getExtendedFamilyCellMap(m).values(),</span>
+<span class="source-line-no">5177</span><span id="line-5177">                  byteTs);</span>
+<span class="source-line-no">5178</span><span id="line-5178">              }</span>
+<span class="source-line-no">5179</span><span id="line-5179">            }</span>
+<span class="source-line-no">5180</span><span id="line-5180">            // And else 'delete' is not needed since it already does a second get, and sets the</span>
+<span class="source-line-no">5181</span><span id="line-5181">            // timestamp from get (see prepareDeleteTimestamps).</span>
+<span class="source-line-no">5182</span><span id="line-5182">          }</span>
+<span class="source-line-no">5183</span><span id="line-5183">          // All edits for the given row (across all column families) must happen atomically.</span>
+<span class="source-line-no">5184</span><span id="line-5184">          Result r;</span>
+<span class="source-line-no">5185</span><span id="line-5185">          if (mutation != null) {</span>
+<span class="source-line-no">5186</span><span id="line-5186">            r = mutate(mutation, true, nonceGroup, nonce).getResult();</span>
+<span class="source-line-no">5187</span><span id="line-5187">          } else {</span>
+<span class="source-line-no">5188</span><span id="line-5188">            r = mutateRow(rowMutations, nonceGroup, nonce);</span>
+<span class="source-line-no">5189</span><span id="line-5189">          }</span>
+<span class="source-line-no">5190</span><span id="line-5190">          this.checkAndMutateChecksPassed.increment();</span>
+<span class="source-line-no">5191</span><span id="line-5191">          return new CheckAndMutateResult(true, r);</span>
+<span class="source-line-no">5192</span><span id="line-5192">        }</span>
+<span class="source-line-no">5193</span><span id="line-5193">        this.checkAndMutateChecksFailed.increment();</span>
+<span class="source-line-no">5194</span><span id="line-5194">        return new CheckAndMutateResult(false, null);</span>
+<span class="source-line-no">5195</span><span id="line-5195">      } finally {</span>
+<span class="source-line-no">5196</span><span id="line-5196">        rowLock.release();</span>
+<span class="source-line-no">5197</span><span id="line-5197">      }</span>
+<span class="source-line-no">5198</span><span id="line-5198">    } finally {</span>
+<span class="source-line-no">5199</span><span id="line-5199">      closeRegionOperation();</span>
+<span class="source-line-no">5200</span><span id="line-5200">    }</span>
+<span class="source-line-no">5201</span><span id="line-5201">  }</span>
+<span class="source-line-no">5202</span><span id="line-5202"></span>
+<span class="source-line-no">5203</span><span id="line-5203">  private void checkMutationType(final Mutation mutation) throws DoNotRetryIOException {</span>
+<span class="source-line-no">5204</span><span id="line-5204">    if (</span>
+<span class="source-line-no">5205</span><span id="line-5205">      !(mutation instanceof Put) &amp;&amp; !(mutation instanceof Delete)</span>
+<span class="source-line-no">5206</span><span id="line-5206">        &amp;&amp; !(mutation instanceof Increment) &amp;&amp; !(mutation instanceof Append)</span>
+<span class="source-line-no">5207</span><span id="line-5207">    ) {</span>
+<span class="source-line-no">5208</span><span id="line-5208">      throw new org.apache.hadoop.hbase.DoNotRetryIOException(</span>
+<span class="source-line-no">5209</span><span id="line-5209">        "Action must be Put or Delete or Increment or Delete");</span>
+<span class="source-line-no">5210</span><span id="line-5210">    }</span>
+<span class="source-line-no">5211</span><span id="line-5211">  }</span>
+<span class="source-line-no">5212</span><span id="line-5212"></span>
+<span class="source-line-no">5213</span><span id="line-5213">  private void checkRow(final Row action, final byte[] row) throws DoNotRetryIOException {</span>
+<span class="source-line-no">5214</span><span id="line-5214">    if (!Bytes.equals(row, action.getRow())) {</span>
+<span class="source-line-no">5215</span><span id="line-5215">      throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");</span>
+<span class="source-line-no">5216</span><span id="line-5216">    }</span>
+<span class="source-line-no">5217</span><span id="line-5217">  }</span>
+<span class="source-line-no">5218</span><span id="line-5218"></span>
+<span class="source-line-no">5219</span><span id="line-5219">  private boolean matches(final CompareOperator op, final int compareResult) {</span>
+<span class="source-line-no">5220</span><span id="line-5220">    boolean matches = false;</span>
+<span class="source-line-no">5221</span><span id="line-5221">    switch (op) {</span>
+<span class="source-line-no">5222</span><span id="line-5222">      case LESS:</span>
+<span class="source-line-no">5223</span><span id="line-5223">        matches = compareResult &lt; 0;</span>
+<span class="source-line-no">5224</span><span id="line-5224">        break;</span>
+<span class="source-line-no">5225</span><span id="line-5225">      case LESS_OR_EQUAL:</span>
+<span class="source-line-no">5226</span><span id="line-5226">        matches = compareResult &lt;= 0;</span>
+<span class="source-line-no">5227</span><span id="line-5227">        break;</span>
+<span class="source-line-no">5228</span><span id="line-5228">      case EQUAL:</span>
+<span class="source-line-no">5229</span><span id="line-5229">        matches = compareResult == 0;</span>
+<span class="source-line-no">5230</span><span id="line-5230">        break;</span>
+<span class="source-line-no">5231</span><span id="line-5231">      case NOT_EQUAL:</span>
+<span class="source-line-no">5232</span><span id="line-5232">        matches = compareResult != 0;</span>
+<span class="source-line-no">5233</span><span id="line-5233">        break;</span>
+<span class="source-line-no">5234</span><span id="line-5234">      case GREATER_OR_EQUAL:</span>
+<span class="source-line-no">5235</span><span id="line-5235">        matches = compareResult &gt;= 0;</span>
+<span class="source-line-no">5236</span><span id="line-5236">        break;</span>
+<span class="source-line-no">5237</span><span id="line-5237">      case GREATER:</span>
+<span class="source-line-no">5238</span><span id="line-5238">        matches = compareResult &gt; 0;</span>
+<span class="source-line-no">5239</span><span id="line-5239">        break;</span>
+<span class="source-line-no">5240</span><span id="line-5240">      default:</span>
+<span class="source-line-no">5241</span><span id="line-5241">        throw new RuntimeException("Unknown Compare op " + op.name());</span>
+<span class="source-line-no">5242</span><span id="line-5242">    }</span>
+<span class="source-line-no">5243</span><span id="line-5243">    return matches;</span>
+<span class="source-line-no">5244</span><span id="line-5244">  }</span>
+<span class="source-line-no">5245</span><span id="line-5245"></span>
+<span class="source-line-no">5246</span><span id="line-5246">  private OperationStatus mutate(Mutation mutation) throws IOException {</span>
+<span class="source-line-no">5247</span><span id="line-5247">    return mutate(mutation, false);</span>
+<span class="source-line-no">5248</span><span id="line-5248">  }</span>
+<span class="source-line-no">5249</span><span id="line-5249"></span>
+<span class="source-line-no">5250</span><span id="line-5250">  private OperationStatus mutate(Mutation mutation, boolean atomic) throws IOException {</span>
+<span class="source-line-no">5251</span><span id="line-5251">    return mutate(mutation, atomic, HConstants.NO_NONCE, HConstants.NO_NONCE);</span>
+<span class="source-line-no">5252</span><span id="line-5252">  }</span>
+<span class="source-line-no">5253</span><span id="line-5253"></span>
+<span class="source-line-no">5254</span><span id="line-5254">  private OperationStatus mutate(Mutation mutation, boolean atomic, long nonceGroup, long nonce)</span>
+<span class="source-line-no">5255</span><span id="line-5255">    throws IOException {</span>
+<span class="source-line-no">5256</span><span id="line-5256">    OperationStatus[] status =</span>
+<span class="source-line-no">5257</span><span id="line-5257">      this.batchMutate(new Mutation[] { mutation }, atomic, nonceGroup, nonce);</span>
+<span class="source-line-no">5258</span><span id="line-5258">    if (status[0].getOperationStatusCode().equals(OperationStatusCode.SANITY_CHECK_FAILURE)) {</span>
+<span class="source-line-no">5259</span><span id="line-5259">      throw new FailedSanityCheckException(status[0].getExceptionMsg());</span>
+<span class="source-line-no">5260</span><span id="line-5260">    } else if (status[0].getOperationStatusCode().equals(OperationStatusCode.BAD_FAMILY)) {</span>
+<span class="source-line-no">5261</span><span id="line-5261">      throw new NoSuchColumnFamilyException(status[0].getExceptionMsg());</span>
+<span class="source-line-no">5262</span><span id="line-5262">    } else if (status[0].getOperationStatusCode().equals(OperationStatusCode.STORE_TOO_BUSY)) {</span>
+<span class="source-line-no">5263</span><span id="line-5263">      throw new RegionTooBusyException(status[0].getExceptionMsg());</span>
+<span class="source-line-no">5264</span><span id="line-5264">    }</span>
+<span class="source-line-no">5265</span><span id="line-5265">    return status[0];</span>
+<span class="source-line-no">5266</span><span id="line-5266">  }</span>
+<span class="source-line-no">5267</span><span id="line-5267"></span>
+<span class="source-line-no">5268</span><span id="line-5268">  /**</span>
+<span class="source-line-no">5269</span><span id="line-5269">   * Complete taking the snapshot on the region. Writes the region info and adds references to the</span>
+<span class="source-line-no">5270</span><span id="line-5270">   * working snapshot directory. TODO for api consistency, consider adding another version with no</span>
+<span class="source-line-no">5271</span><span id="line-5271">   * {@link ForeignExceptionSnare} arg. (In the future other cancellable HRegion methods could</span>
+<span class="source-line-no">5272</span><span id="line-5272">   * eventually add a {@link ForeignExceptionSnare}, or we could do something fancier).</span>
+<span class="source-line-no">5273</span><span id="line-5273">   * @param desc     snapshot description object</span>
+<span class="source-line-no">5274</span><span id="line-5274">   * @param exnSnare ForeignExceptionSnare that captures external exceptions in case we need to bail</span>
+<span class="source-line-no">5275</span><span id="line-5275">   *                 out. This is allowed to be null and will just be ignored in that case.</span>
+<span class="source-line-no">5276</span><span id="line-5276">   * @throws IOException if there is an external or internal error causing the snapshot to fail</span>
+<span class="source-line-no">5277</span><span id="line-5277">   */</span>
+<span class="source-line-no">5278</span><span id="line-5278">  public void addRegionToSnapshot(SnapshotDescription desc, ForeignExceptionSnare exnSnare)</span>
+<span class="source-line-no">5279</span><span id="line-5279">    throws IOException {</span>
+<span class="source-line-no">5280</span><span id="line-5280">    Path rootDir = CommonFSUtils.getRootDir(conf);</span>
+<span class="source-line-no">5281</span><span id="line-5281">    Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);</span>
+<span class="source-line-no">5282</span><span id="line-5282"></span>
+<span class="source-line-no">5283</span><span id="line-5283">    SnapshotManifest manifest =</span>
+<span class="source-line-no">5284</span><span id="line-5284">      SnapshotManifest.create(conf, getFilesystem(), snapshotDir, desc, exnSnare);</span>
+<span class="source-line-no">5285</span><span id="line-5285">    manifest.addRegion(this);</span>
+<span class="source-line-no">5286</span><span id="line-5286">  }</span>
+<span class="source-line-no">5287</span><span id="line-5287"></span>
+<span class="source-line-no">5288</span><span id="line-5288">  private void updateSequenceId(final Iterable&lt;List&lt;ExtendedCell&gt;&gt; cellItr, final long sequenceId)</span>
+<span class="source-line-no">5289</span><span id="line-5289">    throws IOException {</span>
+<span class="source-line-no">5290</span><span id="line-5290">    for (List&lt;ExtendedCell&gt; cells : cellItr) {</span>
+<span class="source-line-no">5291</span><span id="line-5291">      if (cells == null) {</span>
+<span class="source-line-no">5292</span><span id="line-5292">        return;</span>
+<span class="source-line-no">5293</span><span id="line-5293">      }</span>
+<span class="source-line-no">5294</span><span id="line-5294">      for (ExtendedCell cell : cells) {</span>
+<span class="source-line-no">5295</span><span id="line-5295">        cell.setSequenceId(sequenceId);</span>
+<span class="source-line-no">5296</span><span id="line-5296">      }</span>
+<span class="source-line-no">5297</span><span id="line-5297">    }</span>
+<span class="source-line-no">5298</span><span id="line-5298">  }</span>
+<span class="source-line-no">5299</span><span id="line-5299"></span>
+<span class="source-line-no">5300</span><span id="line-5300">  /**</span>
+<span class="source-line-no">5301</span><span id="line-5301">   * Replace any cell timestamps set to {@link org.apache.hadoop.hbase.HConstants#LATEST_TIMESTAMP}</span>
+<span class="source-line-no">5302</span><span id="line-5302">   * provided current timestamp.</span>
+<span class="source-line-no">5303</span><span id="line-5303">   */</span>
+<span class="source-line-no">5304</span><span id="line-5304">  private static void updateCellTimestamps(final Iterable&lt;List&lt;ExtendedCell&gt;&gt; cellItr,</span>
+<span class="source-line-no">5305</span><span id="line-5305">    final byte[] now) throws IOException {</span>
+<span class="source-line-no">5306</span><span id="line-5306">    for (List&lt;ExtendedCell&gt; cells : cellItr) {</span>
+<span class="source-line-no">5307</span><span id="line-5307">      if (cells == null) {</span>
+<span class="source-line-no">5308</span><span id="line-5308">        continue;</span>
+<span class="source-line-no">5309</span><span id="line-5309">      }</span>
+<span class="source-line-no">5310</span><span id="line-5310">      // Optimization: 'foreach' loop is not used. See:</span>
+<span class="source-line-no">5311</span><span id="line-5311">      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects</span>
+<span class="source-line-no">5312</span><span id="line-5312">      assert cells instanceof RandomAccess;</span>
+<span class="source-line-no">5313</span><span id="line-5313">      int listSize = cells.size();</span>
+<span class="source-line-no">5314</span><span id="line-5314">      for (int i = 0; i &lt; listSize; i++) {</span>
+<span class="source-line-no">5315</span><span id="line-5315">        PrivateCellUtil.updateLatestStamp(cells.get(i), now);</span>
+<span class="source-line-no">5316</span><span id="line-5316">      }</span>
+<span class="source-line-no">5317</span><span id="line-5317">    }</span>
+<span class="source-line-no">5318</span><span id="line-5318">  }</span>
+<span class="source-line-no">5319</span><span id="line-5319"></span>
+<span class="source-line-no">5320</span><span id="line-5320">  /**</span>
+<span class="source-line-no">5321</span><span id="line-5321">   * Possibly rewrite incoming cell tags.</span>
+<span class="source-line-no">5322</span><span id="line-5322">   */</span>
+<span class="source-line-no">5323</span><span id="line-5323">  private void rewriteCellTags(Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; familyMap, final Mutation m) {</span>
+<span class="source-line-no">5324</span><span id="line-5324">    // Check if we have any work to do and early out otherwise</span>
+<span class="source-line-no">5325</span><span id="line-5325">    // Update these checks as more logic is added here</span>
+<span class="source-line-no">5326</span><span id="line-5326">    if (m.getTTL() == Long.MAX_VALUE) {</span>
+<span class="source-line-no">5327</span><span id="line-5327">      return;</span>
 <span class="source-line-no">5328</span><span id="line-5328">    }</span>
-<span class="source-line-no">5329</span><span id="line-5329">  }</span>
-<span class="source-line-no">5330</span><span id="line-5330"></span>
-<span class="source-line-no">5331</span><span id="line-5331">  public void setReadsEnabled(boolean readsEnabled) {</span>
-<span class="source-line-no">5332</span><span id="line-5332">    if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {</span>
-<span class="source-line-no">5333</span><span id="line-5333">      LOG.info("Enabling reads for {}", getRegionInfo().getEncodedName());</span>
-<span class="source-line-no">5334</span><span id="line-5334">    }</span>
-<span class="source-line-no">5335</span><span id="line-5335">    this.writestate.setReadsEnabled(readsEnabled);</span>
-<span class="source-line-no">5336</span><span id="line-5336">  }</span>
-<span class="source-line-no">5337</span><span id="line-5337"></span>
-<span class="source-line-no">5338</span><span id="line-5338">  /**</span>
-<span class="source-line-no">5339</span><span id="line-5339">   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be</span>
-<span class="source-line-no">5340</span><span id="line-5340">   *              set; when set we will run operations that make sense in the increment/append</span>
-<span class="source-line-no">5341</span><span id="line-5341">   *              scenario but that do not make sense otherwise.</span>
-<span class="source-line-no">5342</span><span id="line-5342">   */</span>
-<span class="source-line-no">5343</span><span id="line-5343">  private void applyToMemStore(HStore store, List&lt;ExtendedCell&gt; cells, boolean delta,</span>
-<span class="source-line-no">5344</span><span id="line-5344">    MemStoreSizing memstoreAccounting) {</span>
-<span class="source-line-no">5345</span><span id="line-5345">    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!</span>
-<span class="source-line-no">5346</span><span id="line-5346">    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;</span>
-<span class="source-line-no">5347</span><span id="line-5347">    if (upsert) {</span>
-<span class="source-line-no">5348</span><span id="line-5348">      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);</span>
-<span class="source-line-no">5349</span><span id="line-5349">    } else {</span>
-<span class="source-line-no">5350</span><span id="line-5350">      store.add(cells, memstoreAccounting);</span>
-<span class="source-line-no">5351</span><span id="line-5351">    }</span>
-<span class="source-line-no">5352</span><span id="line-5352">  }</span>
-<span class="source-line-no">5353</span><span id="line-5353"></span>
-<span class="source-line-no">5354</span><span id="line-5354">  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)</span>
-<span class="source-line-no">5355</span><span id="line-5355">    throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {</span>
-<span class="source-line-no">5356</span><span id="line-5356">    for (byte[] family : families) {</span>
-<span class="source-line-no">5357</span><span id="line-5357">      checkFamily(family, durability);</span>
-<span class="source-line-no">5358</span><span id="line-5358">    }</span>
-<span class="source-line-no">5359</span><span id="line-5359">  }</span>
-<span class="source-line-no">5360</span><span id="line-5360"></span>
-<span class="source-line-no">5361</span><span id="line-5361">  private void checkFamily(final byte[] family, Durability durability)</span>
-<span class="source-line-no">5362</span><span id="line-5362">    throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {</span>
-<span class="source-line-no">5363</span><span id="line-5363">    checkFamily(family);</span>
-<span class="source-line-no">5364</span><span id="line-5364">    if (</span>
-<span class="source-line-no">5365</span><span id="line-5365">      durability.equals(Durability.SKIP_WAL)</span>
-<span class="source-line-no">5366</span><span id="line-5366">        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope() != HConstants.REPLICATION_SCOPE_LOCAL</span>
-<span class="source-line-no">5367</span><span id="line-5367">    ) {</span>
-<span class="source-line-no">5368</span><span id="line-5368">      throw new InvalidMutationDurabilityException(</span>
-<span class="source-line-no">5369</span><span id="line-5369">        "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)</span>
-<span class="source-line-no">5370</span><span id="line-5370">          + " need replication");</span>
-<span class="source-line-no">5371</span><span id="line-5371">    }</span>
-<span class="source-line-no">5372</span><span id="line-5372">  }</span>
-<span class="source-line-no">5373</span><span id="line-5373"></span>
-<span class="source-line-no">5374</span><span id="line-5374">  private void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {</span>
-<span class="source-line-no">5375</span><span id="line-5375">    if (!this.htableDescriptor.hasColumnFamily(family)) {</span>
-<span class="source-line-no">5376</span><span id="line-5376">      throw new NoSuchColumnFamilyException("Column family " + Bytes.toString(family)</span>
-<span class="source-line-no">5377</span><span id="line-5377">        + " does not exist in region " + this + " in table " + this.htableDescriptor);</span>
-<span class="source-line-no">5378</span><span id="line-5378">    }</span>
-<span class="source-line-no">5379</span><span id="line-5379">  }</span>
-<span class="source-line-no">5380</span><span id="line-5380"></span>
-<span class="source-line-no">5381</span><span id="line-5381">  /**</span>
-<span class="source-line-no">5382</span><span id="line-5382">   * Check the collection of families for valid timestamps</span>
-<span class="source-line-no">5383</span><span id="line-5383">   * @param now current timestamp</span>
-<span class="source-line-no">5384</span><span id="line-5384">   */</span>
-<span class="source-line-no">5385</span><span id="line-5385">  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)</span>
-<span class="source-line-no">5386</span><span id="line-5386">    throws FailedSanityCheckException {</span>
-<span class="source-line-no">5387</span><span id="line-5387">    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {</span>
-<span class="source-line-no">5388</span><span id="line-5388">      return;</span>
-<span class="source-line-no">5389</span><span id="line-5389">    }</span>
-<span class="source-line-no">5390</span><span id="line-5390">    long maxTs = now + timestampSlop;</span>
-<span class="source-line-no">5391</span><span id="line-5391">    for (List&lt;Cell&gt; kvs : familyMap.values()) {</span>
-<span class="source-line-no">5392</span><span id="line-5392">      // Optimization: 'foreach' loop is not used. See:</span>
-<span class="source-line-no">5393</span><span id="line-5393">      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects</span>
-<span class="source-line-no">5394</span><span id="line-5394">      assert kvs instanceof RandomAccess;</span>
-<span class="source-line-no">5395</span><span id="line-5395">      int listSize = kvs.size();</span>
-<span class="source-line-no">5396</span><span id="line-5396">      for (int i = 0; i &lt; listSize; i++) {</span>
-<span class="source-line-no">5397</span><span id="line-5397">        Cell cell = kvs.get(i);</span>
-<span class="source-line-no">5398</span><span id="line-5398">        // see if the user-side TS is out of range. latest = server-side</span>
-<span class="source-line-no">5399</span><span id="line-5399">        long ts = cell.getTimestamp();</span>
-<span class="source-line-no">5400</span><span id="line-5400">        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {</span>
-<span class="source-line-no">5401</span><span id="line-5401">          throw new FailedSanityCheckException(</span>
-<span class="source-line-no">5402</span><span id="line-5402">            "Timestamp for KV out of range " + cell + " (too.new=" + timestampSlop + ")");</span>
-<span class="source-line-no">5403</span><span id="line-5403">        }</span>
-<span class="source-line-no">5404</span><span id="line-5404">      }</span>
-<span class="source-line-no">5405</span><span id="line-5405">    }</span>
-<span class="source-line-no">5406</span><span id="line-5406">  }</span>
-<span class="source-line-no">5407</span><span id="line-5407"></span>
-<span class="source-line-no">5408</span><span id="line-5408">  /*</span>
-<span class="source-line-no">5409</span><span id="line-5409">   * @return True if size is over the flush threshold</span>
-<span class="source-line-no">5410</span><span id="line-5410">   */</span>
-<span class="source-line-no">5411</span><span id="line-5411">  private boolean isFlushSize(MemStoreSize size) {</span>
-<span class="source-line-no">5412</span><span id="line-5412">    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();</span>
-<span class="source-line-no">5413</span><span id="line-5413">  }</span>
-<span class="source-line-no">5414</span><span id="line-5414"></span>
-<span class="source-line-no">5415</span><span id="line-5415">  private void deleteRecoveredEdits(FileSystem fs, Iterable&lt;Path&gt; files) throws IOException {</span>
-<span class="source-line-no">5416</span><span id="line-5416">    for (Path file : files) {</span>
-<span class="source-line-no">5417</span><span id="line-5417">      if (!fs.delete(file, false)) {</span>
-<span class="source-line-no">5418</span><span id="line-5418">        LOG.error("Failed delete of {}", file);</span>
-<span class="source-line-no">5419</span><span id="line-5419">      } else {</span>
-<span class="source-line-no">5420</span><span id="line-5420">        LOG.debug("Deleted recovered.edits file={}", file);</span>
-<span class="source-line-no">5421</span><span id="line-5421">      }</span>
-<span class="source-line-no">5422</span><span id="line-5422">    }</span>
-<span class="source-line-no">5423</span><span id="line-5423">  }</span>
-<span class="source-line-no">5424</span><span id="line-5424"></span>
-<span class="source-line-no">5425</span><span id="line-5425">  /**</span>
-<span class="source-line-no">5426</span><span id="line-5426">   * Read the edits put under this region by wal splitting process. Put the recovered edits back up</span>
-<span class="source-line-no">5427</span><span id="line-5427">   * into this region.</span>
-<span class="source-line-no">5428</span><span id="line-5428">   * &lt;p&gt;</span>
-<span class="source-line-no">5429</span><span id="line-5429">   * We can ignore any wal message that has a sequence ID that's equal to or lower than minSeqId.</span>
-<span class="source-line-no">5430</span><span id="line-5430">   * (Because we know such messages are already reflected in the HFiles.)</span>
-<span class="source-line-no">5431</span><span id="line-5431">   * &lt;p&gt;</span>
-<span class="source-line-no">5432</span><span id="line-5432">   * While this is running we are putting pressure on memory yet we are outside of our usual</span>
-<span class="source-line-no">5433</span><span id="line-5433">   * accounting because we are not yet an onlined region (this stuff is being run as part of Region</span>
-<span class="source-line-no">5434</span><span id="line-5434">   * initialization). This means that if we're up against global memory limits, we'll not be flagged</span>
-<span class="source-line-no">5435</span><span id="line-5435">   * to flush because we are not online. We can't be flushed by usual mechanisms anyways; we're not</span>
-<span class="source-line-no">5436</span><span id="line-5436">   * yet online so our relative sequenceids are not yet aligned with WAL sequenceids -- not till we</span>
-<span class="source-line-no">5437</span><span id="line-5437">   * come up online, post processing of split edits.</span>
-<span class="source-line-no">5438</span><span id="line-5438">   * &lt;p&gt;</span>
-<span class="source-line-no">5439</span><span id="line-5439">   * But to help relieve memory pressure, at least manage our own heap size flushing if are in</span>
-<span class="source-line-no">5440</span><span id="line-5440">   * excess of per-region limits. Flushing, though, we have to be careful and avoid using the</span>
-<span class="source-line-no">5441</span><span id="line-5441">   * regionserver/wal sequenceid. Its running on a different line to whats going on in here in this</span>
-<span class="source-line-no">5442</span><span id="line-5442">   * region context so if we crashed replaying these edits, but in the midst had a flush that used</span>
-<span class="source-line-no">5443</span><span id="line-5443">   * the regionserver wal with a sequenceid in excess of whats going on in here in this region and</span>
-<span class="source-line-no">5444</span><span id="line-5444">   * with its split editlogs, then we could miss edits the next time we go to recover. So, we have</span>
-<span class="source-line-no">5445</span><span id="line-5445">   * to flush inline, using seqids that make sense in a this single region context only -- until we</span>
-<span class="source-line-no">5446</span><span id="line-5446">   * online.</span>
-<span class="source-line-no">5447</span><span id="line-5447">   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of the maxSeqId</span>
-<span class="source-line-no">5448</span><span id="line-5448">   *                         for the store to be applied, else its skipped.</span>
-<span class="source-line-no">5449</span><span id="line-5449">   * @return the sequence id of the last edit added to this region out of the recovered edits log or</span>
-<span class="source-line-no">5450</span><span id="line-5450">   *         &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.</span>
-<span class="source-line-no">5451</span><span id="line-5451">   */</span>
-<span class="source-line-no">5452</span><span id="line-5452">  long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,</span>
-<span class="source-line-no">5453</span><span id="line-5453">    final CancelableProgressable reporter, final MonitoredTask status) throws IOException {</span>
-<span class="source-line-no">5454</span><span id="line-5454">    long minSeqIdForTheRegion = -1;</span>
-<span class="source-line-no">5455</span><span id="line-5455">    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {</span>
-<span class="source-line-no">5456</span><span id="line-5456">      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {</span>
-<span class="source-line-no">5457</span><span id="line-5457">        minSeqIdForTheRegion = maxSeqIdInStore;</span>
-<span class="source-line-no">5458</span><span id="line-5458">      }</span>
-<span class="source-line-no">5459</span><span id="line-5459">    }</span>
-<span class="source-line-no">5460</span><span id="line-5460">    long seqId = minSeqIdForTheRegion;</span>
-<span class="source-line-no">5461</span><span id="line-5461">    String specialRecoveredEditsDirStr = conf.get(SPECIAL_RECOVERED_EDITS_DIR);</span>
-<span class="source-line-no">5462</span><span id="line-5462">    if (org.apache.commons.lang3.StringUtils.isBlank(specialRecoveredEditsDirStr)) {</span>
-<span class="source-line-no">5463</span><span id="line-5463">      FileSystem walFS = getWalFileSystem();</span>
-<span class="source-line-no">5464</span><span id="line-5464">      FileSystem rootFS = getFilesystem();</span>
-<span class="source-line-no">5465</span><span id="line-5465">      Path wrongRegionWALDir = CommonFSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),</span>
-<span class="source-line-no">5466</span><span id="line-5466">        getRegionInfo().getEncodedName());</span>
-<span class="source-line-no">5467</span><span id="line-5467">      Path regionWALDir = getWALRegionDir();</span>
-<span class="source-line-no">5468</span><span id="line-5468">      Path regionDir =</span>
-<span class="source-line-no">5469</span><span id="line-5469">        FSUtils.getRegionDirFromRootDir(CommonFSUtils.getRootDir(conf), getRegionInfo());</span>
+<span class="source-line-no">5329</span><span id="line-5329"></span>
+<span class="source-line-no">5330</span><span id="line-5330">    // From this point we know we have some work to do</span>
+<span class="source-line-no">5331</span><span id="line-5331">    for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; e : familyMap.entrySet()) {</span>
+<span class="source-line-no">5332</span><span id="line-5332">      List&lt;ExtendedCell&gt; cells = e.getValue();</span>
+<span class="source-line-no">5333</span><span id="line-5333">      assert cells instanceof RandomAccess;</span>
+<span class="source-line-no">5334</span><span id="line-5334">      int listSize = cells.size();</span>
+<span class="source-line-no">5335</span><span id="line-5335">      for (int i = 0; i &lt; listSize; i++) {</span>
+<span class="source-line-no">5336</span><span id="line-5336">        ExtendedCell cell = cells.get(i);</span>
+<span class="source-line-no">5337</span><span id="line-5337">        List&lt;Tag&gt; newTags = TagUtil.carryForwardTags(null, cell);</span>
+<span class="source-line-no">5338</span><span id="line-5338">        newTags = TagUtil.carryForwardTTLTag(newTags, m.getTTL());</span>
+<span class="source-line-no">5339</span><span id="line-5339">        // Rewrite the cell with the updated set of tags</span>
+<span class="source-line-no">5340</span><span id="line-5340">        cells.set(i, PrivateCellUtil.createCell(cell, newTags));</span>
+<span class="source-line-no">5341</span><span id="line-5341">      }</span>
+<span class="source-line-no">5342</span><span id="line-5342">    }</span>
+<span class="source-line-no">5343</span><span id="line-5343">  }</span>
+<span class="source-line-no">5344</span><span id="line-5344"></span>
+<span class="source-line-no">5345</span><span id="line-5345">  /**</span>
+<span class="source-line-no">5346</span><span id="line-5346">   * Check if resources to support an update.</span>
+<span class="source-line-no">5347</span><span id="line-5347">   * &lt;p/&gt;</span>
+<span class="source-line-no">5348</span><span id="line-5348">   * We throw RegionTooBusyException if above memstore limit and expect client to retry using some</span>
+<span class="source-line-no">5349</span><span id="line-5349">   * kind of backoff</span>
+<span class="source-line-no">5350</span><span id="line-5350">   */</span>
+<span class="source-line-no">5351</span><span id="line-5351">  private void checkResources() throws RegionTooBusyException {</span>
+<span class="source-line-no">5352</span><span id="line-5352">    // If catalog region, do not impose resource constraints or block updates.</span>
+<span class="source-line-no">5353</span><span id="line-5353">    if (this.getRegionInfo().isMetaRegion()) {</span>
+<span class="source-line-no">5354</span><span id="line-5354">      return;</span>
+<span class="source-line-no">5355</span><span id="line-5355">    }</span>
+<span class="source-line-no">5356</span><span id="line-5356"></span>
+<span class="source-line-no">5357</span><span id="line-5357">    MemStoreSize mss = this.memStoreSizing.getMemStoreSize();</span>
+<span class="source-line-no">5358</span><span id="line-5358">    if (mss.getHeapSize() + mss.getOffHeapSize() &gt; this.blockingMemStoreSize) {</span>
+<span class="source-line-no">5359</span><span id="line-5359">      blockedRequestsCount.increment();</span>
+<span class="source-line-no">5360</span><span id="line-5360">      requestFlush();</span>
+<span class="source-line-no">5361</span><span id="line-5361">      // Don't print current limit because it will vary too much. The message is used as a key</span>
+<span class="source-line-no">5362</span><span id="line-5362">      // over in RetriesExhaustedWithDetailsException processing.</span>
+<span class="source-line-no">5363</span><span id="line-5363">      final String regionName =</span>
+<span class="source-line-no">5364</span><span id="line-5364">        this.getRegionInfo() == null ? "unknown" : this.getRegionInfo().getEncodedName();</span>
+<span class="source-line-no">5365</span><span id="line-5365">      final String serverName = this.getRegionServerServices() == null</span>
+<span class="source-line-no">5366</span><span id="line-5366">        ? "unknown"</span>
+<span class="source-line-no">5367</span><span id="line-5367">        : (this.getRegionServerServices().getServerName() == null</span>
+<span class="source-line-no">5368</span><span id="line-5368">          ? "unknown"</span>
+<span class="source-line-no">5369</span><span id="line-5369">          : this.getRegionServerServices().getServerName().toString());</span>
+<span class="source-line-no">5370</span><span id="line-5370">      RegionTooBusyException rtbe = new RegionTooBusyException("Over memstore limit="</span>
+<span class="source-line-no">5371</span><span id="line-5371">        + org.apache.hadoop.hbase.procedure2.util.StringUtils.humanSize(this.blockingMemStoreSize)</span>
+<span class="source-line-no">5372</span><span id="line-5372">        + ", regionName=" + regionName + ", server=" + serverName);</span>
+<span class="source-line-no">5373</span><span id="line-5373">      LOG.warn("Region is too busy due to exceeding memstore size limit.", rtbe);</span>
+<span class="source-line-no">5374</span><span id="line-5374">      throw rtbe;</span>
+<span class="source-line-no">5375</span><span id="line-5375">    }</span>
+<span class="source-line-no">5376</span><span id="line-5376">  }</span>
+<span class="source-line-no">5377</span><span id="line-5377"></span>
+<span class="source-line-no">5378</span><span id="line-5378">  /**</span>
+<span class="source-line-no">5379</span><span id="line-5379">   * @throws IOException Throws exception if region is in read-only mode.</span>
+<span class="source-line-no">5380</span><span id="line-5380">   */</span>
+<span class="source-line-no">5381</span><span id="line-5381">  private void checkReadOnly() throws IOException {</span>
+<span class="source-line-no">5382</span><span id="line-5382">    if (isReadOnly()) {</span>
+<span class="source-line-no">5383</span><span id="line-5383">      throw new DoNotRetryIOException("region is read only");</span>
+<span class="source-line-no">5384</span><span id="line-5384">    }</span>
+<span class="source-line-no">5385</span><span id="line-5385">  }</span>
+<span class="source-line-no">5386</span><span id="line-5386"></span>
+<span class="source-line-no">5387</span><span id="line-5387">  private void checkReadsEnabled() throws IOException {</span>
+<span class="source-line-no">5388</span><span id="line-5388">    if (!this.writestate.readsEnabled) {</span>
+<span class="source-line-no">5389</span><span id="line-5389">      throw new IOException(getRegionInfo().getEncodedName()</span>
+<span class="source-line-no">5390</span><span id="line-5390">        + ": The region's reads are disabled. Cannot serve the request");</span>
+<span class="source-line-no">5391</span><span id="line-5391">    }</span>
+<span class="source-line-no">5392</span><span id="line-5392">  }</span>
+<span class="source-line-no">5393</span><span id="line-5393"></span>
+<span class="source-line-no">5394</span><span id="line-5394">  public void setReadsEnabled(boolean readsEnabled) {</span>
+<span class="source-line-no">5395</span><span id="line-5395">    if (readsEnabled &amp;&amp; !this.writestate.readsEnabled) {</span>
+<span class="source-line-no">5396</span><span id="line-5396">      LOG.info("Enabling reads for {}", getRegionInfo().getEncodedName());</span>
+<span class="source-line-no">5397</span><span id="line-5397">    }</span>
+<span class="source-line-no">5398</span><span id="line-5398">    this.writestate.setReadsEnabled(readsEnabled);</span>
+<span class="source-line-no">5399</span><span id="line-5399">  }</span>
+<span class="source-line-no">5400</span><span id="line-5400"></span>
+<span class="source-line-no">5401</span><span id="line-5401">  /**</span>
+<span class="source-line-no">5402</span><span id="line-5402">   * @param delta If we are doing delta changes -- e.g. increment/append -- then this flag will be</span>
+<span class="source-line-no">5403</span><span id="line-5403">   *              set; when set we will run operations that make sense in the increment/append</span>
+<span class="source-line-no">5404</span><span id="line-5404">   *              scenario but that do not make sense otherwise.</span>
+<span class="source-line-no">5405</span><span id="line-5405">   */</span>
+<span class="source-line-no">5406</span><span id="line-5406">  private void applyToMemStore(HStore store, List&lt;ExtendedCell&gt; cells, boolean delta,</span>
+<span class="source-line-no">5407</span><span id="line-5407">    MemStoreSizing memstoreAccounting) {</span>
+<span class="source-line-no">5408</span><span id="line-5408">    // Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!</span>
+<span class="source-line-no">5409</span><span id="line-5409">    boolean upsert = delta &amp;&amp; store.getColumnFamilyDescriptor().getMaxVersions() == 1;</span>
+<span class="source-line-no">5410</span><span id="line-5410">    if (upsert) {</span>
+<span class="source-line-no">5411</span><span id="line-5411">      store.upsert(cells, getSmallestReadPoint(), memstoreAccounting);</span>
+<span class="source-line-no">5412</span><span id="line-5412">    } else {</span>
+<span class="source-line-no">5413</span><span id="line-5413">      store.add(cells, memstoreAccounting);</span>
+<span class="source-line-no">5414</span><span id="line-5414">    }</span>
+<span class="source-line-no">5415</span><span id="line-5415">  }</span>
+<span class="source-line-no">5416</span><span id="line-5416"></span>
+<span class="source-line-no">5417</span><span id="line-5417">  private void checkFamilies(Collection&lt;byte[]&gt; families, Durability durability)</span>
+<span class="source-line-no">5418</span><span id="line-5418">    throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {</span>
+<span class="source-line-no">5419</span><span id="line-5419">    for (byte[] family : families) {</span>
+<span class="source-line-no">5420</span><span id="line-5420">      checkFamily(family, durability);</span>
+<span class="source-line-no">5421</span><span id="line-5421">    }</span>
+<span class="source-line-no">5422</span><span id="line-5422">  }</span>
+<span class="source-line-no">5423</span><span id="line-5423"></span>
+<span class="source-line-no">5424</span><span id="line-5424">  private void checkFamily(final byte[] family, Durability durability)</span>
+<span class="source-line-no">5425</span><span id="line-5425">    throws NoSuchColumnFamilyException, InvalidMutationDurabilityException {</span>
+<span class="source-line-no">5426</span><span id="line-5426">    checkFamily(family);</span>
+<span class="source-line-no">5427</span><span id="line-5427">    if (</span>
+<span class="source-line-no">5428</span><span id="line-5428">      durability.equals(Durability.SKIP_WAL)</span>
+<span class="source-line-no">5429</span><span id="line-5429">        &amp;&amp; htableDescriptor.getColumnFamily(family).getScope() != HConstants.REPLICATION_SCOPE_LOCAL</span>
+<span class="source-line-no">5430</span><span id="line-5430">    ) {</span>
+<span class="source-line-no">5431</span><span id="line-5431">      throw new InvalidMutationDurabilityException(</span>
+<span class="source-line-no">5432</span><span id="line-5432">        "Mutation's durability is SKIP_WAL but table's column family " + Bytes.toString(family)</span>
+<span class="source-line-no">5433</span><span id="line-5433">          + " need replication");</span>
+<span class="source-line-no">5434</span><span id="line-5434">    }</span>
+<span class="source-line-no">5435</span><span id="line-5435">  }</span>
+<span class="source-line-no">5436</span><span id="line-5436"></span>
+<span class="source-line-no">5437</span><span id="line-5437">  private void checkFamily(final byte[] family) throws NoSuchColumnFamilyException {</span>
+<span class="source-line-no">5438</span><span id="line-5438">    if (!this.htableDescriptor.hasColumnFamily(family)) {</span>
+<span class="source-line-no">5439</span><span id="line-5439">      throw new NoSuchColumnFamilyException("Column family " + Bytes.toString(family)</span>
+<span class="source-line-no">5440</span><span id="line-5440">        + " does not exist in region " + this + " in table " + this.htableDescriptor);</span>
+<span class="source-line-no">5441</span><span id="line-5441">    }</span>
+<span class="source-line-no">5442</span><span id="line-5442">  }</span>
+<span class="source-line-no">5443</span><span id="line-5443"></span>
+<span class="source-line-no">5444</span><span id="line-5444">  /**</span>
+<span class="source-line-no">5445</span><span id="line-5445">   * Check the collection of families for valid timestamps</span>
+<span class="source-line-no">5446</span><span id="line-5446">   * @param now current timestamp</span>
+<span class="source-line-no">5447</span><span id="line-5447">   */</span>
+<span class="source-line-no">5448</span><span id="line-5448">  public void checkTimestamps(final Map&lt;byte[], List&lt;Cell&gt;&gt; familyMap, long now)</span>
+<span class="source-line-no">5449</span><span id="line-5449">    throws FailedSanityCheckException {</span>
+<span class="source-line-no">5450</span><span id="line-5450">    if (timestampSlop == HConstants.LATEST_TIMESTAMP) {</span>
+<span class="source-line-no">5451</span><span id="line-5451">      return;</span>
+<span class="source-line-no">5452</span><span id="line-5452">    }</span>
+<span class="source-line-no">5453</span><span id="line-5453">    long maxTs = now + timestampSlop;</span>
+<span class="source-line-no">5454</span><span id="line-5454">    for (List&lt;Cell&gt; kvs : familyMap.values()) {</span>
+<span class="source-line-no">5455</span><span id="line-5455">      // Optimization: 'foreach' loop is not used. See:</span>
+<span class="source-line-no">5456</span><span id="line-5456">      // HBASE-12023 HRegion.applyFamilyMapToMemstore creates too many iterator objects</span>
+<span class="source-line-no">5457</span><span id="line-5457">      assert kvs instanceof RandomAccess;</span>
+<span class="source-line-no">5458</span><span id="line-5458">      int listSize = kvs.size();</span>
+<span class="source-line-no">5459</span><span id="line-5459">      for (int i = 0; i &lt; listSize; i++) {</span>
+<span class="source-line-no">5460</span><span id="line-5460">        Cell cell = kvs.get(i);</span>
+<span class="source-line-no">5461</span><span id="line-5461">        // see if the user-side TS is out of range. latest = server-side</span>
+<span class="source-line-no">5462</span><span id="line-5462">        long ts = cell.getTimestamp();</span>
+<span class="source-line-no">5463</span><span id="line-5463">        if (ts != HConstants.LATEST_TIMESTAMP &amp;&amp; ts &gt; maxTs) {</span>
+<span class="source-line-no">5464</span><span id="line-5464">          throw new FailedSanityCheckException(</span>
+<span class="source-line-no">5465</span><span id="line-5465">            "Timestamp for KV out of range " + cell + " (too.new=" + timestampSlop + ")");</span>
+<span class="source-line-no">5466</span><span id="line-5466">        }</span>
+<span class="source-line-no">5467</span><span id="line-5467">      }</span>
+<span class="source-line-no">5468</span><span id="line-5468">    }</span>
+<span class="source-line-no">5469</span><span id="line-5469">  }</span>
 <span class="source-line-no">5470</span><span id="line-5470"></span>
-<span class="source-line-no">5471</span><span id="line-5471">      // We made a mistake in HBASE-20734 so we need to do this dirty hack...</span>
-<span class="source-line-no">5472</span><span id="line-5472">      NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =</span>
-<span class="source-line-no">5473</span><span id="line-5473">        WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);</span>
-<span class="source-line-no">5474</span><span id="line-5474">      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,</span>
-<span class="source-line-no">5475</span><span id="line-5475">        filesUnderWrongRegionWALDir, reporter, regionDir));</span>
-<span class="source-line-no">5476</span><span id="line-5476">      // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear</span>
-<span class="source-line-no">5477</span><span id="line-5477">      // under the root dir even if walDir is set.</span>
-<span class="source-line-no">5478</span><span id="line-5478">      NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();</span>
-<span class="source-line-no">5479</span><span id="line-5479">      if (!regionWALDir.equals(regionDir)) {</span>
-<span class="source-line-no">5480</span><span id="line-5480">        filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);</span>
-<span class="source-line-no">5481</span><span id="line-5481">        seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,</span>
-<span class="source-line-no">5482</span><span id="line-5482">          filesUnderRootDir, reporter, regionDir));</span>
-<span class="source-line-no">5483</span><span id="line-5483">      }</span>
-<span class="source-line-no">5484</span><span id="line-5484"></span>
-<span class="source-line-no">5485</span><span id="line-5485">      NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);</span>
-<span class="source-line-no">5486</span><span id="line-5486">      seqId = Math.max(seqId,</span>
-<span class="source-line-no">5487</span><span id="line-5487">        replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS, files, reporter, regionWALDir));</span>
-<span class="source-line-no">5488</span><span id="line-5488">      if (seqId &gt; minSeqIdForTheRegion) {</span>
-<span class="source-line-no">5489</span><span id="line-5489">        // Then we added some edits to memory. Flush and cleanup split edit files.</span>
-<span class="source-line-no">5490</span><span id="line-5490">        internalFlushcache(null, seqId, stores.values(), status, false,</span>
-<span class="source-line-no">5491</span><span id="line-5491">          FlushLifeCycleTracker.DUMMY);</span>
-<span class="source-line-no">5492</span><span id="line-5492">      }</span>
-<span class="source-line-no">5493</span><span id="line-5493">      // Now delete the content of recovered edits. We're done w/ them.</span>
-<span class="source-line-no">5494</span><span id="line-5494">      if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {</span>
-<span class="source-line-no">5495</span><span id="line-5495">        // For debugging data loss issues!</span>
-<span class="source-line-no">5496</span><span id="line-5496">        // If this flag is set, make use of the hfile archiving by making recovered.edits a fake</span>
-<span class="source-line-no">5497</span><span id="line-5497">        // column family. Have to fake out file type too by casting our recovered.edits as</span>
-<span class="source-line-no">5498</span><span id="line-5498">        // storefiles</span>
-<span class="source-line-no">5499</span><span id="line-5499">        String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();</span>
-<span class="source-line-no">5500</span><span id="line-5500">        StoreContext storeContext =</span>
-<span class="source-line-no">5501</span><span id="line-5501">          StoreContext.getBuilder().withRegionFileSystem(getRegionFileSystem()).build();</span>
-<span class="source-line-no">5502</span><span id="line-5502">        StoreFileTracker sft = StoreFileTrackerFactory.create(this.conf, true, storeContext);</span>
-<span class="source-line-no">5503</span><span id="line-5503">        Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());</span>
-<span class="source-line-no">5504</span><span id="line-5504">        for (Path file : files) {</span>
-<span class="source-line-no">5505</span><span id="line-5505">          fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true, sft));</span>
-<span class="source-line-no">5506</span><span id="line-5506">        }</span>
-<span class="source-line-no">5507</span><span id="line-5507">        getRegionWALFileSystem().archiveRecoveredEdits(fakeFamilyName, fakeStoreFiles);</span>
-<span class="source-line-no">5508</span><span id="line-5508">      } else {</span>
-<span class="source-line-no">5509</span><span id="line-5509">        deleteRecoveredEdits(walFS, Iterables.concat(files, filesUnderWrongRegionWALDir));</span>
-<span class="source-line-no">5510</span><span id="line-5510">        deleteRecoveredEdits(rootFS, filesUnderRootDir);</span>
-<span class="source-line-no">5511</span><span id="line-5511">      }</span>
-<span class="source-line-no">5512</span><span id="line-5512">    } else {</span>
-<span class="source-line-no">5513</span><span id="line-5513">      Path recoveredEditsDir = new Path(specialRecoveredEditsDirStr);</span>
-<span class="source-line-no">5514</span><span id="line-5514">      FileSystem fs = recoveredEditsDir.getFileSystem(conf);</span>
-<span class="source-line-no">5515</span><span id="line-5515">      FileStatus[] files = fs.listStatus(recoveredEditsDir);</span>
-<span class="source-line-no">5516</span><span id="line-5516">      LOG.debug("Found {} recovered edits file(s) under {}", files == null ? 0 : files.length,</span>
-<span class="source-line-no">5517</span><span id="line-5517">        recoveredEditsDir);</span>
-<span class="source-line-no">5518</span><span id="line-5518">      if (files != null) {</span>
-<span class="source-line-no">5519</span><span id="line-5519">        for (FileStatus file : files) {</span>
-<span class="source-line-no">5520</span><span id="line-5520">          // it is safe to trust the zero-length in this case because we've been through rename and</span>
-<span class="source-line-no">5521</span><span id="line-5521">          // lease recovery in the above.</span>
-<span class="source-line-no">5522</span><span id="line-5522">          if (isZeroLengthThenDelete(fs, file, file.getPath())) {</span>
-<span class="source-line-no">5523</span><span id="line-5523">            continue;</span>
-<span class="source-line-no">5524</span><span id="line-5524">          }</span>
-<span class="source-line-no">5525</span><span id="line-5525">          seqId =</span>
-<span class="source-line-no">5526</span><span id="line-5526">            Math.max(seqId, replayRecoveredEdits(file.getPath(), maxSeqIdInStores, reporter, fs));</span>
-<span class="source-line-no">5527</span><span id="line-5527">        }</span>
-<span class="source-line-no">5528</span><span id="line-5528">      }</span>
-<span class="source-line-no">5529</span><span id="line-5529">      if (seqId &gt; minSeqIdForTheRegion) {</span>
-<span class="source-line-no">5530</span><span id="line-5530">        // Then we added some edits to memory. Flush and cleanup split edit files.</span>
-<span class="source-line-no">5531</span><span id="line-5531">        internalFlushcache(null, seqId, stores.values(), status, false,</span>
-<span class="source-line-no">5532</span><span id="line-5532">          FlushLifeCycleTracker.DUMMY);</span>
-<span class="source-line-no">5533</span><span id="line-5533">      }</span>
-<span class="source-line-no">5534</span><span id="line-5534">      deleteRecoveredEdits(fs,</span>
-<span class="source-line-no">5535</span><span id="line-5535">        Stream.of(files).map(FileStatus::getPath).collect(Collectors.toList()));</span>
-<span class="source-line-no">5536</span><span id="line-5536">    }</span>
-<span class="source-line-no">5537</span><span id="line-5537"></span>
-<span class="source-line-no">5538</span><span id="line-5538">    return seqId;</span>
-<span class="source-line-no">5539</span><span id="line-5539">  }</span>
-<span class="source-line-no">5540</span><span id="line-5540"></span>
-<span class="source-line-no">5541</span><span id="line-5541">  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,</span>
-<span class="source-line-no">5542</span><span id="line-5542">    final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)</span>
-<span class="source-line-no">5543</span><span id="line-5543">    throws IOException {</span>
-<span class="source-line-no">5544</span><span id="line-5544">    long seqid = minSeqIdForTheRegion;</span>
-<span class="source-line-no">5545</span><span id="line-5545">    if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">5546</span><span id="line-5546">      LOG.debug("Found " + (files == null ? 0 : files.size()) + " recovered edits file(s) under "</span>
-<span class="source-line-no">5547</span><span id="line-5547">        + regionDir);</span>
-<span class="source-line-no">5548</span><span id="line-5548">    }</span>
-<span class="source-line-no">5549</span><span id="line-5549"></span>
-<span class="source-line-no">5550</span><span id="line-5550">    if (files == null || files.isEmpty()) {</span>
-<span class="source-line-no">5551</span><span id="line-5551">      return minSeqIdForTheRegion;</span>
-<span class="source-line-no">5552</span><span id="line-5552">    }</span>
-<span class="source-line-no">5553</span><span id="line-5553"></span>
-<span class="source-line-no">5554</span><span id="line-5554">    for (Path edits : files) {</span>
-<span class="source-line-no">5555</span><span id="line-5555">      if (edits == null || !fs.exists(edits)) {</span>
-<span class="source-line-no">5556</span><span id="line-5556">        LOG.warn("Null or non-existent edits file: " + edits);</span>
-<span class="source-line-no">5557</span><span id="line-5557">        continue;</span>
-<span class="source-line-no">5558</span><span id="line-5558">      }</span>
-<span class="source-line-no">5559</span><span id="line-5559">      if (isZeroLengthThenDelete(fs, fs.getFileStatus(edits), edits)) {</span>
-<span class="source-line-no">5560</span><span id="line-5560">        continue;</span>
-<span class="source-line-no">5561</span><span id="line-5561">      }</span>
-<span class="source-line-no">5562</span><span id="line-5562"></span>
-<span class="source-line-no">5563</span><span id="line-5563">      long maxSeqId;</span>
-<span class="source-line-no">5564</span><span id="line-5564">      String fileName = edits.getName();</span>
-<span class="source-line-no">5565</span><span id="line-5565">      maxSeqId = Math.abs(Long.parseLong(fileName));</span>
-<span class="source-line-no">5566</span><span id="line-5566">      if (maxSeqId &lt;= minSeqIdForTheRegion) {</span>
-<span class="source-line-no">5567</span><span id="line-5567">        if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">5568</span><span id="line-5568">          String msg = "Maximum sequenceid for this wal is " + maxSeqId</span>
-<span class="source-line-no">5569</span><span id="line-5569">            + " and minimum sequenceid for the region " + this + "  is " + minSeqIdForTheRegion</span>
-<span class="source-line-no">5570</span><span id="line-5570">            + ", skipped the whole file, path=" + edits;</span>
-<span class="source-line-no">5571</span><span id="line-5571">          LOG.debug(msg);</span>
-<span class="source-line-no">5572</span><span id="line-5572">        }</span>
-<span class="source-line-no">5573</span><span id="line-5573">        continue;</span>
+<span class="source-line-no">5471</span><span id="line-5471">  /*</span>
+<span class="source-line-no">5472</span><span id="line-5472">   * @return True if size is over the flush threshold</span>
+<span class="source-line-no">5473</span><span id="line-5473">   */</span>
+<span class="source-line-no">5474</span><span id="line-5474">  private boolean isFlushSize(MemStoreSize size) {</span>
+<span class="source-line-no">5475</span><span id="line-5475">    return size.getHeapSize() + size.getOffHeapSize() &gt; getMemStoreFlushSize();</span>
+<span class="source-line-no">5476</span><span id="line-5476">  }</span>
+<span class="source-line-no">5477</span><span id="line-5477"></span>
+<span class="source-line-no">5478</span><span id="line-5478">  private void deleteRecoveredEdits(FileSystem fs, Iterable&lt;Path&gt; files) throws IOException {</span>
+<span class="source-line-no">5479</span><span id="line-5479">    for (Path file : files) {</span>
+<span class="source-line-no">5480</span><span id="line-5480">      if (!fs.delete(file, false)) {</span>
+<span class="source-line-no">5481</span><span id="line-5481">        LOG.error("Failed delete of {}", file);</span>
+<span class="source-line-no">5482</span><span id="line-5482">      } else {</span>
+<span class="source-line-no">5483</span><span id="line-5483">        LOG.debug("Deleted recovered.edits file={}", file);</span>
+<span class="source-line-no">5484</span><span id="line-5484">      }</span>
+<span class="source-line-no">5485</span><span id="line-5485">    }</span>
+<span class="source-line-no">5486</span><span id="line-5486">  }</span>
+<span class="source-line-no">5487</span><span id="line-5487"></span>
+<span class="source-line-no">5488</span><span id="line-5488">  /**</span>
+<span class="source-line-no">5489</span><span id="line-5489">   * Read the edits put under this region by wal splitting process. Put the recovered edits back up</span>
+<span class="source-line-no">5490</span><span id="line-5490">   * into this region.</span>
+<span class="source-line-no">5491</span><span id="line-5491">   * &lt;p&gt;</span>
+<span class="source-line-no">5492</span><span id="line-5492">   * We can ignore any wal message that has a sequence ID that's equal to or lower than minSeqId.</span>
+<span class="source-line-no">5493</span><span id="line-5493">   * (Because we know such messages are already reflected in the HFiles.)</span>
+<span class="source-line-no">5494</span><span id="line-5494">   * &lt;p&gt;</span>
+<span class="source-line-no">5495</span><span id="line-5495">   * While this is running we are putting pressure on memory yet we are outside of our usual</span>
+<span class="source-line-no">5496</span><span id="line-5496">   * accounting because we are not yet an onlined region (this stuff is being run as part of Region</span>
+<span class="source-line-no">5497</span><span id="line-5497">   * initialization). This means that if we're up against global memory limits, we'll not be flagged</span>
+<span class="source-line-no">5498</span><span id="line-5498">   * to flush because we are not online. We can't be flushed by usual mechanisms anyways; we're not</span>
+<span class="source-line-no">5499</span><span id="line-5499">   * yet online so our relative sequenceids are not yet aligned with WAL sequenceids -- not till we</span>
+<span class="source-line-no">5500</span><span id="line-5500">   * come up online, post processing of split edits.</span>
+<span class="source-line-no">5501</span><span id="line-5501">   * &lt;p&gt;</span>
+<span class="source-line-no">5502</span><span id="line-5502">   * But to help relieve memory pressure, at least manage our own heap size flushing if are in</span>
+<span class="source-line-no">5503</span><span id="line-5503">   * excess of per-region limits. Flushing, though, we have to be careful and avoid using the</span>
+<span class="source-line-no">5504</span><span id="line-5504">   * regionserver/wal sequenceid. Its running on a different line to whats going on in here in this</span>
+<span class="source-line-no">5505</span><span id="line-5505">   * region context so if we crashed replaying these edits, but in the midst had a flush that used</span>
+<span class="source-line-no">5506</span><span id="line-5506">   * the regionserver wal with a sequenceid in excess of whats going on in here in this region and</span>
+<span class="source-line-no">5507</span><span id="line-5507">   * with its split editlogs, then we could miss edits the next time we go to recover. So, we have</span>
+<span class="source-line-no">5508</span><span id="line-5508">   * to flush inline, using seqids that make sense in a this single region context only -- until we</span>
+<span class="source-line-no">5509</span><span id="line-5509">   * online.</span>
+<span class="source-line-no">5510</span><span id="line-5510">   * @param maxSeqIdInStores Any edit found in split editlogs needs to be in excess of the maxSeqId</span>
+<span class="source-line-no">5511</span><span id="line-5511">   *                         for the store to be applied, else its skipped.</span>
+<span class="source-line-no">5512</span><span id="line-5512">   * @return the sequence id of the last edit added to this region out of the recovered edits log or</span>
+<span class="source-line-no">5513</span><span id="line-5513">   *         &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.</span>
+<span class="source-line-no">5514</span><span id="line-5514">   */</span>
+<span class="source-line-no">5515</span><span id="line-5515">  long replayRecoveredEditsIfAny(Map&lt;byte[], Long&gt; maxSeqIdInStores,</span>
+<span class="source-line-no">5516</span><span id="line-5516">    final CancelableProgressable reporter, final MonitoredTask status) throws IOException {</span>
+<span class="source-line-no">5517</span><span id="line-5517">    long minSeqIdForTheRegion = -1;</span>
+<span class="source-line-no">5518</span><span id="line-5518">    for (Long maxSeqIdInStore : maxSeqIdInStores.values()) {</span>
+<span class="source-line-no">5519</span><span id="line-5519">      if (maxSeqIdInStore &lt; minSeqIdForTheRegion || minSeqIdForTheRegion == -1) {</span>
+<span class="source-line-no">5520</span><span id="line-5520">        minSeqIdForTheRegion = maxSeqIdInStore;</span>
+<span class="source-line-no">5521</span><span id="line-5521">      }</span>
+<span class="source-line-no">5522</span><span id="line-5522">    }</span>
+<span class="source-line-no">5523</span><span id="line-5523">    long seqId = minSeqIdForTheRegion;</span>
+<span class="source-line-no">5524</span><span id="line-5524">    String specialRecoveredEditsDirStr = conf.get(SPECIAL_RECOVERED_EDITS_DIR);</span>
+<span class="source-line-no">5525</span><span id="line-5525">    if (org.apache.commons.lang3.StringUtils.isBlank(specialRecoveredEditsDirStr)) {</span>
+<span class="source-line-no">5526</span><span id="line-5526">      FileSystem walFS = getWalFileSystem();</span>
+<span class="source-line-no">5527</span><span id="line-5527">      FileSystem rootFS = getFilesystem();</span>
+<span class="source-line-no">5528</span><span id="line-5528">      Path wrongRegionWALDir = CommonFSUtils.getWrongWALRegionDir(conf, getRegionInfo().getTable(),</span>
+<span class="source-line-no">5529</span><span id="line-5529">        getRegionInfo().getEncodedName());</span>
+<span class="source-line-no">5530</span><span id="line-5530">      Path regionWALDir = getWALRegionDir();</span>
+<span class="source-line-no">5531</span><span id="line-5531">      Path regionDir =</span>
+<span class="source-line-no">5532</span><span id="line-5532">        FSUtils.getRegionDirFromRootDir(CommonFSUtils.getRootDir(conf), getRegionInfo());</span>
+<span class="source-line-no">5533</span><span id="line-5533"></span>
+<span class="source-line-no">5534</span><span id="line-5534">      // We made a mistake in HBASE-20734 so we need to do this dirty hack...</span>
+<span class="source-line-no">5535</span><span id="line-5535">      NavigableSet&lt;Path&gt; filesUnderWrongRegionWALDir =</span>
+<span class="source-line-no">5536</span><span id="line-5536">        WALSplitUtil.getSplitEditFilesSorted(walFS, wrongRegionWALDir);</span>
+<span class="source-line-no">5537</span><span id="line-5537">      seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS,</span>
+<span class="source-line-no">5538</span><span id="line-5538">        filesUnderWrongRegionWALDir, reporter, regionDir));</span>
+<span class="source-line-no">5539</span><span id="line-5539">      // This is to ensure backwards compatability with HBASE-20723 where recovered edits can appear</span>
+<span class="source-line-no">5540</span><span id="line-5540">      // under the root dir even if walDir is set.</span>
+<span class="source-line-no">5541</span><span id="line-5541">      NavigableSet&lt;Path&gt; filesUnderRootDir = Collections.emptyNavigableSet();</span>
+<span class="source-line-no">5542</span><span id="line-5542">      if (!regionWALDir.equals(regionDir)) {</span>
+<span class="source-line-no">5543</span><span id="line-5543">        filesUnderRootDir = WALSplitUtil.getSplitEditFilesSorted(rootFS, regionDir);</span>
+<span class="source-line-no">5544</span><span id="line-5544">        seqId = Math.max(seqId, replayRecoveredEditsForPaths(minSeqIdForTheRegion, rootFS,</span>
+<span class="source-line-no">5545</span><span id="line-5545">          filesUnderRootDir, reporter, regionDir));</span>
+<span class="source-line-no">5546</span><span id="line-5546">      }</span>
+<span class="source-line-no">5547</span><span id="line-5547"></span>
+<span class="source-line-no">5548</span><span id="line-5548">      NavigableSet&lt;Path&gt; files = WALSplitUtil.getSplitEditFilesSorted(walFS, regionWALDir);</span>
+<span class="source-line-no">5549</span><span id="line-5549">      seqId = Math.max(seqId,</span>
+<span class="source-line-no">5550</span><span id="line-5550">        replayRecoveredEditsForPaths(minSeqIdForTheRegion, walFS, files, reporter, regionWALDir));</span>
+<span class="source-line-no">5551</span><span id="line-5551">      if (seqId &gt; minSeqIdForTheRegion) {</span>
+<span class="source-line-no">5552</span><span id="line-5552">        // Then we added some edits to memory. Flush and cleanup split edit files.</span>
+<span class="source-line-no">5553</span><span id="line-5553">        internalFlushcache(null, seqId, stores.values(), status, false,</span>
+<span class="source-line-no">5554</span><span id="line-5554">          FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">5555</span><span id="line-5555">      }</span>
+<span class="source-line-no">5556</span><span id="line-5556">      // Now delete the content of recovered edits. We're done w/ them.</span>
+<span class="source-line-no">5557</span><span id="line-5557">      if (files.size() &gt; 0 &amp;&amp; this.conf.getBoolean("hbase.region.archive.recovered.edits", false)) {</span>
+<span class="source-line-no">5558</span><span id="line-5558">        // For debugging data loss issues!</span>
+<span class="source-line-no">5559</span><span id="line-5559">        // If this flag is set, make use of the hfile archiving by making recovered.edits a fake</span>
+<span class="source-line-no">5560</span><span id="line-5560">        // column family. Have to fake out file type too by casting our recovered.edits as</span>
+<span class="source-line-no">5561</span><span id="line-5561">        // storefiles</span>
+<span class="source-line-no">5562</span><span id="line-5562">        String fakeFamilyName = WALSplitUtil.getRegionDirRecoveredEditsDir(regionWALDir).getName();</span>
+<span class="source-line-no">5563</span><span id="line-5563">        StoreContext storeContext =</span>
+<span class="source-line-no">5564</span><span id="line-5564">          StoreContext.getBuilder().withRegionFileSystem(getRegionFileSystem()).build();</span>
+<span class="source-line-no">5565</span><span id="line-5565">        StoreFileTracker sft = StoreFileTrackerFactory.create(this.conf, true, storeContext);</span>
+<span class="source-line-no">5566</span><span id="line-5566">        Set&lt;HStoreFile&gt; fakeStoreFiles = new HashSet&lt;&gt;(files.size());</span>
+<span class="source-line-no">5567</span><span id="line-5567">        for (Path file : files) {</span>
+<span class="source-line-no">5568</span><span id="line-5568">          fakeStoreFiles.add(new HStoreFile(walFS, file, this.conf, null, null, true, sft));</span>
+<span class="source-line-no">5569</span><span id="line-5569">        }</span>
+<span class="source-line-no">5570</span><span id="line-5570">        getRegionWALFileSystem().archiveRecoveredEdits(fakeFamilyName, fakeStoreFiles);</span>
+<span class="source-line-no">5571</span><span id="line-5571">      } else {</span>
+<span class="source-line-no">5572</span><span id="line-5572">        deleteRecoveredEdits(walFS, Iterables.concat(files, filesUnderWrongRegionWALDir));</span>
+<span class="source-line-no">5573</span><span id="line-5573">        deleteRecoveredEdits(rootFS, filesUnderRootDir);</span>
 <span class="source-line-no">5574</span><span id="line-5574">      }</span>
-<span class="source-line-no">5575</span><span id="line-5575"></span>
-<span class="source-line-no">5576</span><span id="line-5576">      try {</span>
-<span class="source-line-no">5577</span><span id="line-5577">        // replay the edits. Replay can return -1 if everything is skipped, only update</span>
-<span class="source-line-no">5578</span><span id="line-5578">        // if seqId is greater</span>
-<span class="source-line-no">5579</span><span id="line-5579">        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));</span>
-<span class="source-line-no">5580</span><span id="line-5580">      } catch (IOException e) {</span>
-<span class="source-line-no">5581</span><span id="line-5581">        handleException(fs, edits, e);</span>
-<span class="source-line-no">5582</span><span id="line-5582">      }</span>
-<span class="source-line-no">5583</span><span id="line-5583">    }</span>
-<span class="source-line-no">5584</span><span id="line-5584">    return seqid;</span>
-<span class="source-line-no">5585</span><span id="line-5585">  }</span>
-<span class="source-line-no">5586</span><span id="line-5586"></span>
-<span class="source-line-no">5587</span><span id="line-5587">  private void handleException(FileSystem fs, Path edits, IOException e) throws IOException {</span>
-<span class="source-line-no">5588</span><span id="line-5588">    boolean skipErrors = conf.getBoolean(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,</span>
-<span class="source-line-no">5589</span><span id="line-5589">      conf.getBoolean("hbase.skip.errors", HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));</span>
-<span class="source-line-no">5590</span><span id="line-5590">    if (conf.get("hbase.skip.errors") != null) {</span>
-<span class="source-line-no">5591</span><span id="line-5591">      LOG.warn("The property 'hbase.skip.errors' has been deprecated. Please use "</span>
-<span class="source-line-no">5592</span><span id="line-5592">        + HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");</span>
-<span class="source-line-no">5593</span><span id="line-5593">    }</span>
-<span class="source-line-no">5594</span><span id="line-5594">    if (skipErrors) {</span>
-<span class="source-line-no">5595</span><span id="line-5595">      Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);</span>
-<span class="source-line-no">5596</span><span id="line-5596">      LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + "=true so continuing. Renamed "</span>
-<span class="source-line-no">5597</span><span id="line-5597">        + edits + " as " + p, e);</span>
-<span class="source-line-no">5598</span><span id="line-5598">    } else {</span>
-<span class="source-line-no">5599</span><span id="line-5599">      throw e;</span>
-<span class="source-line-no">5600</span><span id="line-5600">    }</span>
-<span class="source-line-no">5601</span><span id="line-5601">  }</span>
-<span class="source-line-no">5602</span><span id="line-5602"></span>
-<span class="source-line-no">5603</span><span id="line-5603">  /**</span>
-<span class="source-line-no">5604</span><span id="line-5604">   * @param edits            File of recovered edits.</span>
-<span class="source-line-no">5605</span><span id="line-5605">   * @param maxSeqIdInStores Maximum sequenceid found in each store. Edits in wal must be larger</span>
-<span class="source-line-no">5606</span><span id="line-5606">   *                         than this to be replayed for each store.</span>
-<span class="source-line-no">5607</span><span id="line-5607">   * @return the sequence id of the last edit added to this region out of the recovered edits log or</span>
-<span class="source-line-no">5608</span><span id="line-5608">   *         &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.</span>
-<span class="source-line-no">5609</span><span id="line-5609">   */</span>
-<span class="source-line-no">5610</span><span id="line-5610">  private long replayRecoveredEdits(final Path edits, Map&lt;byte[], Long&gt; maxSeqIdInStores,</span>
-<span class="source-line-no">5611</span><span id="line-5611">    final CancelableProgressable reporter, FileSystem fs) throws IOException {</span>
-<span class="source-line-no">5612</span><span id="line-5612">    String msg = "Replaying edits from " + edits;</span>
-<span class="source-line-no">5613</span><span id="line-5613">    LOG.info(msg);</span>
-<span class="source-line-no">5614</span><span id="line-5614">    MonitoredTask status = TaskMonitor.get().createStatus(msg);</span>
-<span class="source-line-no">5615</span><span id="line-5615"></span>
-<span class="source-line-no">5616</span><span id="line-5616">    status.setStatus("Opening recovered edits");</span>
-<span class="source-line-no">5617</span><span id="line-5617">    try (WALStreamReader reader = WALFactory.createStreamReader(fs, edits, conf)) {</span>
-<span class="source-line-no">5618</span><span id="line-5618">      long currentEditSeqId = -1;</span>
-<span class="source-line-no">5619</span><span id="line-5619">      long currentReplaySeqId = -1;</span>
-<span class="source-line-no">5620</span><span id="line-5620">      long firstSeqIdInLog = -1;</span>
-<span class="source-line-no">5621</span><span id="line-5621">      long skippedEdits = 0;</span>
-<span class="source-line-no">5622</span><span id="line-5622">      long editsCount = 0;</span>
-<span class="source-line-no">5623</span><span id="line-5623">      long intervalEdits = 0;</span>
-<span class="source-line-no">5624</span><span id="line-5624">      WAL.Entry entry;</span>
-<span class="source-line-no">5625</span><span id="line-5625">      HStore store = null;</span>
-<span class="source-line-no">5626</span><span id="line-5626">      boolean reported_once = false;</span>
-<span class="source-line-no">5627</span><span id="line-5627">      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();</span>
-<span class="source-line-no">5628</span><span id="line-5628"></span>
-<span class="source-line-no">5629</span><span id="line-5629">      try {</span>
-<span class="source-line-no">5630</span><span id="line-5630">        // How many edits seen before we check elapsed time</span>
-<span class="source-line-no">5631</span><span id="line-5631">        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);</span>
-<span class="source-line-no">5632</span><span id="line-5632">        // How often to send a progress report (default 1/2 master timeout)</span>
-<span class="source-line-no">5633</span><span id="line-5633">        int period = this.conf.getInt("hbase.hstore.report.period", 300000);</span>
-<span class="source-line-no">5634</span><span id="line-5634">        long lastReport = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">5635</span><span id="line-5635"></span>
-<span class="source-line-no">5636</span><span id="line-5636">        if (coprocessorHost != null) {</span>
-<span class="source-line-no">5637</span><span id="line-5637">          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);</span>
-<span class="source-line-no">5638</span><span id="line-5638">        }</span>
-<span class="source-line-no">5639</span><span id="line-5639"></span>
-<span class="source-line-no">5640</span><span id="line-5640">        while ((entry = reader.next()) != null) {</span>
-<span class="source-line-no">5641</span><span id="line-5641">          WALKey key = entry.getKey();</span>
-<span class="source-line-no">5642</span><span id="line-5642">          WALEdit val = entry.getEdit();</span>
-<span class="source-line-no">5643</span><span id="line-5643"></span>
-<span class="source-line-no">5644</span><span id="line-5644">          if (ng != null) { // some test, or nonces disabled</span>
-<span class="source-line-no">5645</span><span id="line-5645">            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());</span>
-<span class="source-line-no">5646</span><span id="line-5646">          }</span>
-<span class="source-line-no">5647</span><span id="line-5647"></span>
-<span class="source-line-no">5648</span><span id="line-5648">          if (reporter != null) {</span>
-<span class="source-line-no">5649</span><span id="line-5649">            intervalEdits += val.size();</span>
-<span class="source-line-no">5650</span><span id="line-5650">            if (intervalEdits &gt;= interval) {</span>
-<span class="source-line-no">5651</span><span id="line-5651">              // Number of edits interval reached</span>
-<span class="source-line-no">5652</span><span id="line-5652">              intervalEdits = 0;</span>
-<span class="source-line-no">5653</span><span id="line-5653">              long cur = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">5654</span><span id="line-5654">              if (lastReport + period &lt;= cur) {</span>
-<span class="source-line-no">5655</span><span id="line-5655">                status.setStatus(</span>
-<span class="source-line-no">5656</span><span id="line-5656">                  "Replaying edits..." + " skipped=" + skippedEdits + " edits=" + editsCount);</span>
-<span class="source-line-no">5657</span><span id="line-5657">                // Timeout reached</span>
-<span class="source-line-no">5658</span><span id="line-5658">                if (!reporter.progress()) {</span>
-<span class="source-line-no">5659</span><span id="line-5659">                  msg = "Progressable reporter failed, stopping replay for region " + this;</span>
-<span class="source-line-no">5660</span><span id="line-5660">                  LOG.warn(msg);</span>
-<span class="source-line-no">5661</span><span id="line-5661">                  status.abort(msg);</span>
-<span class="source-line-no">5662</span><span id="line-5662">                  throw new IOException(msg);</span>
-<span class="source-line-no">5663</span><span id="line-5663">                }</span>
-<span class="source-line-no">5664</span><span id="line-5664">                reported_once = true;</span>
-<span class="source-line-no">5665</span><span id="line-5665">                lastReport = cur;</span>
-<span class="source-line-no">5666</span><span id="line-5666">              }</span>
-<span class="source-line-no">5667</span><span id="line-5667">            }</span>
-<span class="source-line-no">5668</span><span id="line-5668">          }</span>
-<span class="source-line-no">5669</span><span id="line-5669"></span>
-<span class="source-line-no">5670</span><span id="line-5670">          if (firstSeqIdInLog == -1) {</span>
-<span class="source-line-no">5671</span><span id="line-5671">            firstSeqIdInLog = key.getSequenceId();</span>
-<span class="source-line-no">5672</span><span id="line-5672">          }</span>
-<span class="source-line-no">5673</span><span id="line-5673">          if (currentEditSeqId &gt; key.getSequenceId()) {</span>
-<span class="source-line-no">5674</span><span id="line-5674">            // when this condition is true, it means we have a serious defect because we need to</span>
-<span class="source-line-no">5675</span><span id="line-5675">            // maintain increasing SeqId for WAL edits per region</span>
-<span class="source-line-no">5676</span><span id="line-5676">            LOG.error(getRegionInfo().getEncodedName() + " : " + "Found decreasing SeqId. PreId="</span>
-<span class="source-line-no">5677</span><span id="line-5677">              + currentEditSeqId + " key=" + key + "; edit=" + val);</span>
-<span class="source-line-no">5678</span><span id="line-5678">          } else {</span>
-<span class="source-line-no">5679</span><span id="line-5679">            currentEditSeqId = key.getSequenceId();</span>
-<span class="source-line-no">5680</span><span id="line-5680">          }</span>
-<span class="source-line-no">5681</span><span id="line-5681">          currentReplaySeqId =</span>
-<span class="source-line-no">5682</span><span id="line-5682">            (key.getOrigLogSeqNum() &gt; 0) ? key.getOrigLogSeqNum() : currentEditSeqId;</span>
-<span class="source-line-no">5683</span><span id="line-5683"></span>
-<span class="source-line-no">5684</span><span id="line-5684">          boolean checkRowWithinBoundary = false;</span>
-<span class="source-line-no">5685</span><span id="line-5685">          // Check this edit is for this region.</span>
-<span class="source-line-no">5686</span><span id="line-5686">          if (</span>
-<span class="source-line-no">5687</span><span id="line-5687">            !Bytes.equals(key.getEncodedRegionName(), this.getRegionInfo().getEncodedNameAsBytes())</span>
-<span class="source-line-no">5688</span><span id="line-5688">          ) {</span>
-<span class="source-line-no">5689</span><span id="line-5689">            checkRowWithinBoundary = true;</span>
-<span class="source-line-no">5690</span><span id="line-5690">          }</span>
+<span class="source-line-no">5575</span><span id="line-5575">    } else {</span>
+<span class="source-line-no">5576</span><span id="line-5576">      Path recoveredEditsDir = new Path(specialRecoveredEditsDirStr);</span>
+<span class="source-line-no">5577</span><span id="line-5577">      FileSystem fs = recoveredEditsDir.getFileSystem(conf);</span>
+<span class="source-line-no">5578</span><span id="line-5578">      FileStatus[] files = fs.listStatus(recoveredEditsDir);</span>
+<span class="source-line-no">5579</span><span id="line-5579">      LOG.debug("Found {} recovered edits file(s) under {}", files == null ? 0 : files.length,</span>
+<span class="source-line-no">5580</span><span id="line-5580">        recoveredEditsDir);</span>
+<span class="source-line-no">5581</span><span id="line-5581">      if (files != null) {</span>
+<span class="source-line-no">5582</span><span id="line-5582">        for (FileStatus file : files) {</span>
+<span class="source-line-no">5583</span><span id="line-5583">          // it is safe to trust the zero-length in this case because we've been through rename and</span>
+<span class="source-line-no">5584</span><span id="line-5584">          // lease recovery in the above.</span>
+<span class="source-line-no">5585</span><span id="line-5585">          if (isZeroLengthThenDelete(fs, file, file.getPath())) {</span>
+<span class="source-line-no">5586</span><span id="line-5586">            continue;</span>
+<span class="source-line-no">5587</span><span id="line-5587">          }</span>
+<span class="source-line-no">5588</span><span id="line-5588">          seqId =</span>
+<span class="source-line-no">5589</span><span id="line-5589">            Math.max(seqId, replayRecoveredEdits(file.getPath(), maxSeqIdInStores, reporter, fs));</span>
+<span class="source-line-no">5590</span><span id="line-5590">        }</span>
+<span class="source-line-no">5591</span><span id="line-5591">      }</span>
+<span class="source-line-no">5592</span><span id="line-5592">      if (seqId &gt; minSeqIdForTheRegion) {</span>
+<span class="source-line-no">5593</span><span id="line-5593">        // Then we added some edits to memory. Flush and cleanup split edit files.</span>
+<span class="source-line-no">5594</span><span id="line-5594">        internalFlushcache(null, seqId, stores.values(), status, false,</span>
+<span class="source-line-no">5595</span><span id="line-5595">          FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">5596</span><span id="line-5596">      }</span>
+<span class="source-line-no">5597</span><span id="line-5597">      deleteRecoveredEdits(fs,</span>
+<span class="source-line-no">5598</span><span id="line-5598">        Stream.of(files).map(FileStatus::getPath).collect(Collectors.toList()));</span>
+<span class="source-line-no">5599</span><span id="line-5599">    }</span>
+<span class="source-line-no">5600</span><span id="line-5600"></span>
+<span class="source-line-no">5601</span><span id="line-5601">    return seqId;</span>
+<span class="source-line-no">5602</span><span id="line-5602">  }</span>
+<span class="source-line-no">5603</span><span id="line-5603"></span>
+<span class="source-line-no">5604</span><span id="line-5604">  private long replayRecoveredEditsForPaths(long minSeqIdForTheRegion, FileSystem fs,</span>
+<span class="source-line-no">5605</span><span id="line-5605">    final NavigableSet&lt;Path&gt; files, final CancelableProgressable reporter, final Path regionDir)</span>
+<span class="source-line-no">5606</span><span id="line-5606">    throws IOException {</span>
+<span class="source-line-no">5607</span><span id="line-5607">    long seqid = minSeqIdForTheRegion;</span>
+<span class="source-line-no">5608</span><span id="line-5608">    if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">5609</span><span id="line-5609">      LOG.debug("Found " + (files == null ? 0 : files.size()) + " recovered edits file(s) under "</span>
+<span class="source-line-no">5610</span><span id="line-5610">        + regionDir);</span>
+<span class="source-line-no">5611</span><span id="line-5611">    }</span>
+<span class="source-line-no">5612</span><span id="line-5612"></span>
+<span class="source-line-no">5613</span><span id="line-5613">    if (files == null || files.isEmpty()) {</span>
+<span class="source-line-no">5614</span><span id="line-5614">      return minSeqIdForTheRegion;</span>
+<span class="source-line-no">5615</span><span id="line-5615">    }</span>
+<span class="source-line-no">5616</span><span id="line-5616"></span>
+<span class="source-line-no">5617</span><span id="line-5617">    for (Path edits : files) {</span>
+<span class="source-line-no">5618</span><span id="line-5618">      if (edits == null || !fs.exists(edits)) {</span>
+<span class="source-line-no">5619</span><span id="line-5619">        LOG.warn("Null or non-existent edits file: " + edits);</span>
+<span class="source-line-no">5620</span><span id="line-5620">        continue;</span>
+<span class="source-line-no">5621</span><span id="line-5621">      }</span>
+<span class="source-line-no">5622</span><span id="line-5622">      if (isZeroLengthThenDelete(fs, fs.getFileStatus(edits), edits)) {</span>
+<span class="source-line-no">5623</span><span id="line-5623">        continue;</span>
+<span class="source-line-no">5624</span><span id="line-5624">      }</span>
+<span class="source-line-no">5625</span><span id="line-5625"></span>
+<span class="source-line-no">5626</span><span id="line-5626">      long maxSeqId;</span>
+<span class="source-line-no">5627</span><span id="line-5627">      String fileName = edits.getName();</span>
+<span class="source-line-no">5628</span><span id="line-5628">      maxSeqId = Math.abs(Long.parseLong(fileName));</span>
+<span class="source-line-no">5629</span><span id="line-5629">      if (maxSeqId &lt;= minSeqIdForTheRegion) {</span>
+<span class="source-line-no">5630</span><span id="line-5630">        if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">5631</span><span id="line-5631">          String msg = "Maximum sequenceid for this wal is " + maxSeqId</span>
+<span class="source-line-no">5632</span><span id="line-5632">            + " and minimum sequenceid for the region " + this + "  is " + minSeqIdForTheRegion</span>
+<span class="source-line-no">5633</span><span id="line-5633">            + ", skipped the whole file, path=" + edits;</span>
+<span class="source-line-no">5634</span><span id="line-5634">          LOG.debug(msg);</span>
+<span class="source-line-no">5635</span><span id="line-5635">        }</span>
+<span class="source-line-no">5636</span><span id="line-5636">        continue;</span>
+<span class="source-line-no">5637</span><span id="line-5637">      }</span>
+<span class="source-line-no">5638</span><span id="line-5638"></span>
+<span class="source-line-no">5639</span><span id="line-5639">      try {</span>
+<span class="source-line-no">5640</span><span id="line-5640">        // replay the edits. Replay can return -1 if everything is skipped, only update</span>
+<span class="source-line-no">5641</span><span id="line-5641">        // if seqId is greater</span>
+<span class="source-line-no">5642</span><span id="line-5642">        seqid = Math.max(seqid, replayRecoveredEdits(edits, maxSeqIdInStores, reporter, fs));</span>
+<span class="source-line-no">5643</span><span id="line-5643">      } catch (IOException e) {</span>
+<span class="source-line-no">5644</span><span id="line-5644">        handleException(fs, edits, e);</span>
+<span class="source-line-no">5645</span><span id="line-5645">      }</span>
+<span class="source-line-no">5646</span><span id="line-5646">    }</span>
+<span class="source-line-no">5647</span><span id="line-5647">    return seqid;</span>
+<span class="source-line-no">5648</span><span id="line-5648">  }</span>
+<span class="source-line-no">5649</span><span id="line-5649"></span>
+<span class="source-line-no">5650</span><span id="line-5650">  private void handleException(FileSystem fs, Path edits, IOException e) throws IOException {</span>
+<span class="source-line-no">5651</span><span id="line-5651">    boolean skipErrors = conf.getBoolean(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS,</span>
+<span class="source-line-no">5652</span><span id="line-5652">      conf.getBoolean("hbase.skip.errors", HConstants.DEFAULT_HREGION_EDITS_REPLAY_SKIP_ERRORS));</span>
+<span class="source-line-no">5653</span><span id="line-5653">    if (conf.get("hbase.skip.errors") != null) {</span>
+<span class="source-line-no">5654</span><span id="line-5654">      LOG.warn("The property 'hbase.skip.errors' has been deprecated. Please use "</span>
+<span class="source-line-no">5655</span><span id="line-5655">        + HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + " instead.");</span>
+<span class="source-line-no">5656</span><span id="line-5656">    }</span>
+<span class="source-line-no">5657</span><span id="line-5657">    if (skipErrors) {</span>
+<span class="source-line-no">5658</span><span id="line-5658">      Path p = WALSplitUtil.moveAsideBadEditsFile(fs, edits);</span>
+<span class="source-line-no">5659</span><span id="line-5659">      LOG.error(HConstants.HREGION_EDITS_REPLAY_SKIP_ERRORS + "=true so continuing. Renamed "</span>
+<span class="source-line-no">5660</span><span id="line-5660">        + edits + " as " + p, e);</span>
+<span class="source-line-no">5661</span><span id="line-5661">    } else {</span>
+<span class="source-line-no">5662</span><span id="line-5662">      throw e;</span>
+<span class="source-line-no">5663</span><span id="line-5663">    }</span>
+<span class="source-line-no">5664</span><span id="line-5664">  }</span>
+<span class="source-line-no">5665</span><span id="line-5665"></span>
+<span class="source-line-no">5666</span><span id="line-5666">  /**</span>
+<span class="source-line-no">5667</span><span id="line-5667">   * @param edits            File of recovered edits.</span>
+<span class="source-line-no">5668</span><span id="line-5668">   * @param maxSeqIdInStores Maximum sequenceid found in each store. Edits in wal must be larger</span>
+<span class="source-line-no">5669</span><span id="line-5669">   *                         than this to be replayed for each store.</span>
+<span class="source-line-no">5670</span><span id="line-5670">   * @return the sequence id of the last edit added to this region out of the recovered edits log or</span>
+<span class="source-line-no">5671</span><span id="line-5671">   *         &lt;code&gt;minSeqId&lt;/code&gt; if nothing added from editlogs.</span>
+<span class="source-line-no">5672</span><span id="line-5672">   */</span>
+<span class="source-line-no">5673</span><span id="line-5673">  private long replayRecoveredEdits(final Path edits, Map&lt;byte[], Long&gt; maxSeqIdInStores,</span>
+<span class="source-line-no">5674</span><span id="line-5674">    final CancelableProgressable reporter, FileSystem fs) throws IOException {</span>
+<span class="source-line-no">5675</span><span id="line-5675">    String msg = "Replaying edits from " + edits;</span>
+<span class="source-line-no">5676</span><span id="line-5676">    LOG.info(msg);</span>
+<span class="source-line-no">5677</span><span id="line-5677">    MonitoredTask status = TaskMonitor.get().createStatus(msg);</span>
+<span class="source-line-no">5678</span><span id="line-5678"></span>
+<span class="source-line-no">5679</span><span id="line-5679">    status.setStatus("Opening recovered edits");</span>
+<span class="source-line-no">5680</span><span id="line-5680">    try (WALStreamReader reader = WALFactory.createStreamReader(fs, edits, conf)) {</span>
+<span class="source-line-no">5681</span><span id="line-5681">      long currentEditSeqId = -1;</span>
+<span class="source-line-no">5682</span><span id="line-5682">      long currentReplaySeqId = -1;</span>
+<span class="source-line-no">5683</span><span id="line-5683">      long firstSeqIdInLog = -1;</span>
+<span class="source-line-no">5684</span><span id="line-5684">      long skippedEdits = 0;</span>
+<span class="source-line-no">5685</span><span id="line-5685">      long editsCount = 0;</span>
+<span class="source-line-no">5686</span><span id="line-5686">      long intervalEdits = 0;</span>
+<span class="source-line-no">5687</span><span id="line-5687">      WAL.Entry entry;</span>
+<span class="source-line-no">5688</span><span id="line-5688">      HStore store = null;</span>
+<span class="source-line-no">5689</span><span id="line-5689">      boolean reported_once = false;</span>
+<span class="source-line-no">5690</span><span id="line-5690">      ServerNonceManager ng = this.rsServices == null ? null : this.rsServices.getNonceManager();</span>
 <span class="source-line-no">5691</span><span id="line-5691"></span>
-<span class="source-line-no">5692</span><span id="line-5692">          boolean flush = false;</span>
-<span class="source-line-no">5693</span><span id="line-5693">          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();</span>
-<span class="source-line-no">5694</span><span id="line-5694">          for (Cell c : val.getCells()) {</span>
-<span class="source-line-no">5695</span><span id="line-5695">            assert c instanceof ExtendedCell;</span>
-<span class="source-line-no">5696</span><span id="line-5696">            ExtendedCell cell = (ExtendedCell) c;</span>
-<span class="source-line-no">5697</span><span id="line-5697">            // Check this edit is for me. Also, guard against writing the special</span>
-<span class="source-line-no">5698</span><span id="line-5698">            // METACOLUMN info such as HBASE::CACHEFLUSH entries</span>
-<span class="source-line-no">5699</span><span id="line-5699">            if (WALEdit.isMetaEditFamily(cell)) {</span>
-<span class="source-line-no">5700</span><span id="line-5700">              // if region names don't match, skipp replaying compaction marker</span>
-<span class="source-line-no">5701</span><span id="line-5701">              if (!checkRowWithinBoundary) {</span>
-<span class="source-line-no">5702</span><span id="line-5702">                // this is a special edit, we should handle it</span>
-<span class="source-line-no">5703</span><span id="line-5703">                CompactionDescriptor compaction = WALEdit.getCompaction(cell);</span>
-<span class="source-line-no">5704</span><span id="line-5704">                if (compaction != null) {</span>
-<span class="source-line-no">5705</span><span id="line-5705">                  // replay the compaction</span>
-<span class="source-line-no">5706</span><span id="line-5706">                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);</span>
-<span class="source-line-no">5707</span><span id="line-5707">                }</span>
-<span class="source-line-no">5708</span><span id="line-5708">              }</span>
-<span class="source-line-no">5709</span><span id="line-5709">              skippedEdits++;</span>
-<span class="source-line-no">5710</span><span id="line-5710">              continue;</span>
-<span class="source-line-no">5711</span><span id="line-5711">            }</span>
-<span class="source-line-no">5712</span><span id="line-5712">            // Figure which store the edit is meant for.</span>
-<span class="source-line-no">5713</span><span id="line-5713">            if (</span>
-<span class="source-line-no">5714</span><span id="line-5714">              store == null</span>
-<span class="source-line-no">5715</span><span id="line-5715">                || !CellUtil.matchingFamily(cell, store.getColumnFamilyDescriptor().getName())</span>
-<span class="source-line-no">5716</span><span id="line-5716">            ) {</span>
-<span class="source-line-no">5717</span><span id="line-5717">              store = getStore(cell);</span>
-<span class="source-line-no">5718</span><span id="line-5718">            }</span>
-<span class="source-line-no">5719</span><span id="line-5719">            if (store == null) {</span>
-<span class="source-line-no">5720</span><span id="line-5720">              // This should never happen. Perhaps schema was changed between</span>
-<span class="source-line-no">5721</span><span id="line-5721">              // crash and redeploy?</span>
-<span class="source-line-no">5722</span><span id="line-5722">              LOG.warn("No family for cell {} in region {}", cell, this);</span>
-<span class="source-line-no">5723</span><span id="line-5723">              skippedEdits++;</span>
-<span class="source-line-no">5724</span><span id="line-5724">              continue;</span>
-<span class="source-line-no">5725</span><span id="line-5725">            }</span>
-<span class="source-line-no">5726</span><span id="line-5726">            if (</span>
-<span class="source-line-no">5727</span><span id="line-5727">              checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(), cell.getRowArray(),</span>
-<span class="source-line-no">5728</span><span id="line-5728">                cell.getRowOffset(), cell.getRowLength())</span>
-<span class="source-line-no">5729</span><span id="line-5729">            ) {</span>
-<span class="source-line-no">5730</span><span id="line-5730">              LOG.warn("Row of {} is not within region boundary for region {}", cell, this);</span>
-<span class="source-line-no">5731</span><span id="line-5731">              skippedEdits++;</span>
-<span class="source-line-no">5732</span><span id="line-5732">              continue;</span>
-<span class="source-line-no">5733</span><span id="line-5733">            }</span>
-<span class="source-line-no">5734</span><span id="line-5734">            // Now, figure if we should skip this edit.</span>
-<span class="source-line-no">5735</span><span id="line-5735">            if (</span>
-<span class="source-line-no">5736</span><span id="line-5736">              key.getSequenceId()</span>
-<span class="source-line-no">5737</span><span id="line-5737">                  &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor().getName())</span>
-<span class="source-line-no">5738</span><span id="line-5738">            ) {</span>
-<span class="source-line-no">5739</span><span id="line-5739">              skippedEdits++;</span>
-<span class="source-line-no">5740</span><span id="line-5740">              continue;</span>
-<span class="source-line-no">5741</span><span id="line-5741">            }</span>
-<span class="source-line-no">5742</span><span id="line-5742">            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);</span>
-<span class="source-line-no">5743</span><span id="line-5743"></span>
-<span class="source-line-no">5744</span><span id="line-5744">            restoreEdit(store, cell, memStoreSizing);</span>
-<span class="source-line-no">5745</span><span id="line-5745">            editsCount++;</span>
-<span class="source-line-no">5746</span><span id="line-5746">          }</span>
-<span class="source-line-no">5747</span><span id="line-5747">          MemStoreSize mss = memStoreSizing.getMemStoreSize();</span>
-<span class="source-line-no">5748</span><span id="line-5748">          incMemStoreSize(mss);</span>
-<span class="source-line-no">5749</span><span id="line-5749">          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());</span>
-<span class="source-line-no">5750</span><span id="line-5750">          if (flush) {</span>
-<span class="source-line-no">5751</span><span id="line-5751">            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,</span>
-<span class="source-line-no">5752</span><span id="line-5752">              FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">5692</span><span id="line-5692">      try {</span>
+<span class="source-line-no">5693</span><span id="line-5693">        // How many edits seen before we check elapsed time</span>
+<span class="source-line-no">5694</span><span id="line-5694">        int interval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000);</span>
+<span class="source-line-no">5695</span><span id="line-5695">        // How often to send a progress report (default 1/2 master timeout)</span>
+<span class="source-line-no">5696</span><span id="line-5696">        int period = this.conf.getInt("hbase.hstore.report.period", 300000);</span>
+<span class="source-line-no">5697</span><span id="line-5697">        long lastReport = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">5698</span><span id="line-5698"></span>
+<span class="source-line-no">5699</span><span id="line-5699">        if (coprocessorHost != null) {</span>
+<span class="source-line-no">5700</span><span id="line-5700">          coprocessorHost.preReplayWALs(this.getRegionInfo(), edits);</span>
+<span class="source-line-no">5701</span><span id="line-5701">        }</span>
+<span class="source-line-no">5702</span><span id="line-5702"></span>
+<span class="source-line-no">5703</span><span id="line-5703">        while ((entry = reader.next()) != null) {</span>
+<span class="source-line-no">5704</span><span id="line-5704">          WALKey key = entry.getKey();</span>
+<span class="source-line-no">5705</span><span id="line-5705">          WALEdit val = entry.getEdit();</span>
+<span class="source-line-no">5706</span><span id="line-5706"></span>
+<span class="source-line-no">5707</span><span id="line-5707">          if (ng != null) { // some test, or nonces disabled</span>
+<span class="source-line-no">5708</span><span id="line-5708">            ng.reportOperationFromWal(key.getNonceGroup(), key.getNonce(), key.getWriteTime());</span>
+<span class="source-line-no">5709</span><span id="line-5709">          }</span>
+<span class="source-line-no">5710</span><span id="line-5710"></span>
+<span class="source-line-no">5711</span><span id="line-5711">          if (reporter != null) {</span>
+<span class="source-line-no">5712</span><span id="line-5712">            intervalEdits += val.size();</span>
+<span class="source-line-no">5713</span><span id="line-5713">            if (intervalEdits &gt;= interval) {</span>
+<span class="source-line-no">5714</span><span id="line-5714">              // Number of edits interval reached</span>
+<span class="source-line-no">5715</span><span id="line-5715">              intervalEdits = 0;</span>
+<span class="source-line-no">5716</span><span id="line-5716">              long cur = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">5717</span><span id="line-5717">              if (lastReport + period &lt;= cur) {</span>
+<span class="source-line-no">5718</span><span id="line-5718">                status.setStatus(</span>
+<span class="source-line-no">5719</span><span id="line-5719">                  "Replaying edits..." + " skipped=" + skippedEdits + " edits=" + editsCount);</span>
+<span class="source-line-no">5720</span><span id="line-5720">                // Timeout reached</span>
+<span class="source-line-no">5721</span><span id="line-5721">                if (!reporter.progress()) {</span>
+<span class="source-line-no">5722</span><span id="line-5722">                  msg = "Progressable reporter failed, stopping replay for region " + this;</span>
+<span class="source-line-no">5723</span><span id="line-5723">                  LOG.warn(msg);</span>
+<span class="source-line-no">5724</span><span id="line-5724">                  status.abort(msg);</span>
+<span class="source-line-no">5725</span><span id="line-5725">                  throw new IOException(msg);</span>
+<span class="source-line-no">5726</span><span id="line-5726">                }</span>
+<span class="source-line-no">5727</span><span id="line-5727">                reported_once = true;</span>
+<span class="source-line-no">5728</span><span id="line-5728">                lastReport = cur;</span>
+<span class="source-line-no">5729</span><span id="line-5729">              }</span>
+<span class="source-line-no">5730</span><span id="line-5730">            }</span>
+<span class="source-line-no">5731</span><span id="line-5731">          }</span>
+<span class="source-line-no">5732</span><span id="line-5732"></span>
+<span class="source-line-no">5733</span><span id="line-5733">          if (firstSeqIdInLog == -1) {</span>
+<span class="source-line-no">5734</span><span id="line-5734">            firstSeqIdInLog = key.getSequenceId();</span>
+<span class="source-line-no">5735</span><span id="line-5735">          }</span>
+<span class="source-line-no">5736</span><span id="line-5736">          if (currentEditSeqId &gt; key.getSequenceId()) {</span>
+<span class="source-line-no">5737</span><span id="line-5737">            // when this condition is true, it means we have a serious defect because we need to</span>
+<span class="source-line-no">5738</span><span id="line-5738">            // maintain increasing SeqId for WAL edits per region</span>
+<span class="source-line-no">5739</span><span id="line-5739">            LOG.error(getRegionInfo().getEncodedName() + " : " + "Found decreasing SeqId. PreId="</span>
+<span class="source-line-no">5740</span><span id="line-5740">              + currentEditSeqId + " key=" + key + "; edit=" + val);</span>
+<span class="source-line-no">5741</span><span id="line-5741">          } else {</span>
+<span class="source-line-no">5742</span><span id="line-5742">            currentEditSeqId = key.getSequenceId();</span>
+<span class="source-line-no">5743</span><span id="line-5743">          }</span>
+<span class="source-line-no">5744</span><span id="line-5744">          currentReplaySeqId =</span>
+<span class="source-line-no">5745</span><span id="line-5745">            (key.getOrigLogSeqNum() &gt; 0) ? key.getOrigLogSeqNum() : currentEditSeqId;</span>
+<span class="source-line-no">5746</span><span id="line-5746"></span>
+<span class="source-line-no">5747</span><span id="line-5747">          boolean checkRowWithinBoundary = false;</span>
+<span class="source-line-no">5748</span><span id="line-5748">          // Check this edit is for this region.</span>
+<span class="source-line-no">5749</span><span id="line-5749">          if (</span>
+<span class="source-line-no">5750</span><span id="line-5750">            !Bytes.equals(key.getEncodedRegionName(), this.getRegionInfo().getEncodedNameAsBytes())</span>
+<span class="source-line-no">5751</span><span id="line-5751">          ) {</span>
+<span class="source-line-no">5752</span><span id="line-5752">            checkRowWithinBoundary = true;</span>
 <span class="source-line-no">5753</span><span id="line-5753">          }</span>
-<span class="source-line-no">5754</span><span id="line-5754">        }</span>
-<span class="source-line-no">5755</span><span id="line-5755"></span>
-<span class="source-line-no">5756</span><span id="line-5756">        if (coprocessorHost != null) {</span>
-<span class="source-line-no">5757</span><span id="line-5757">          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);</span>
-<span class="source-line-no">5758</span><span id="line-5758">        }</span>
-<span class="source-line-no">5759</span><span id="line-5759">      } catch (EOFException eof) {</span>
-<span class="source-line-no">5760</span><span id="line-5760">        if (!conf.getBoolean(RECOVERED_EDITS_IGNORE_EOF, false)) {</span>
-<span class="source-line-no">5761</span><span id="line-5761">          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);</span>
-<span class="source-line-no">5762</span><span id="line-5762">          msg = "EnLongAddered EOF. Most likely due to Master failure during "</span>
-<span class="source-line-no">5763</span><span id="line-5763">            + "wal splitting, so we have this data in another edit. Continuing, but renaming "</span>
-<span class="source-line-no">5764</span><span id="line-5764">            + edits + " as " + p + " for region " + this;</span>
-<span class="source-line-no">5765</span><span id="line-5765">          LOG.warn(msg, eof);</span>
-<span class="source-line-no">5766</span><span id="line-5766">          status.abort(msg);</span>
-<span class="source-line-no">5767</span><span id="line-5767">        } else {</span>
-<span class="source-line-no">5768</span><span id="line-5768">          LOG.warn("EOF while replaying recover edits and config '{}' is true so "</span>
-<span class="source-line-no">5769</span><span id="line-5769">            + "we will ignore it and continue", RECOVERED_EDITS_IGNORE_EOF, eof);</span>
-<span class="source-line-no">5770</span><span id="line-5770">        }</span>
-<span class="source-line-no">5771</span><span id="line-5771">      } catch (IOException ioe) {</span>
-<span class="source-line-no">5772</span><span id="line-5772">        // If the IOE resulted from bad file format,</span>
-<span class="source-line-no">5773</span><span id="line-5773">        // then this problem is idempotent and retrying won't help</span>
-<span class="source-line-no">5774</span><span id="line-5774">        if (ioe.getCause() instanceof ParseException) {</span>
-<span class="source-line-no">5775</span><span id="line-5775">          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);</span>
-<span class="source-line-no">5776</span><span id="line-5776">          msg =</span>
-<span class="source-line-no">5777</span><span id="line-5777">            "File corruption enLongAddered!  " + "Continuing, but renaming " + edits + " as " + p;</span>
-<span class="source-line-no">5778</span><span id="line-5778">          LOG.warn(msg, ioe);</span>
-<span class="source-line-no">5779</span><span id="line-5779">          status.setStatus(msg);</span>
-<span class="source-line-no">5780</span><span id="line-5780">        } else {</span>
-<span class="source-line-no">5781</span><span id="line-5781">          status.abort(StringUtils.stringifyException(ioe));</span>
-<span class="source-line-no">5782</span><span id="line-5782">          // other IO errors may be transient (bad network connection,</span>
-<span class="source-line-no">5783</span><span id="line-5783">          // checksum exception on one datanode, etc). throw &amp; retry</span>
-<span class="source-line-no">5784</span><span id="line-5784">          throw ioe;</span>
-<span class="source-line-no">5785</span><span id="line-5785">        }</span>
-<span class="source-line-no">5786</span><span id="line-5786">      }</span>
-<span class="source-line-no">5787</span><span id="line-5787">      if (reporter != null &amp;&amp; !reported_once) {</span>
-<span class="source-line-no">5788</span><span id="line-5788">        reporter.progress();</span>
-<span class="source-line-no">5789</span><span id="line-5789">      }</span>
-<span class="source-line-no">5790</span><span id="line-5790">      msg = "Applied " + editsCount + ", skipped " + skippedEdits + ", firstSequenceIdInLog="</span>
-<span class="source-line-no">5791</span><span id="line-5791">        + firstSeqIdInLog + ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;</span>
-<span class="source-line-no">5792</span><span id="line-5792">      status.markComplete(msg);</span>
-<span class="source-line-no">5793</span><span id="line-5793">      LOG.debug(msg);</span>
-<span class="source-line-no">5794</span><span id="line-5794">      return currentEditSeqId;</span>
-<span class="source-line-no">5795</span><span id="line-5795">    } finally {</span>
-<span class="source-line-no">5796</span><span id="line-5796">      status.cleanup();</span>
-<span class="source-line-no">5797</span><span id="line-5797">    }</span>
-<span class="source-line-no">5798</span><span id="line-5798">  }</span>
-<span class="source-line-no">5799</span><span id="line-5799"></span>
-<span class="source-line-no">5800</span><span id="line-5800">  /**</span>
-<span class="source-line-no">5801</span><span id="line-5801">   * Call to complete a compaction. Its for the case where we find in the WAL a compaction that was</span>
-<span class="source-line-no">5802</span><span id="line-5802">   * not finished. We could find one recovering a WAL after a regionserver crash. See HBASE-2331.</span>
-<span class="source-line-no">5803</span><span id="line-5803">   */</span>
-<span class="source-line-no">5804</span><span id="line-5804">  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,</span>
-<span class="source-line-no">5805</span><span id="line-5805">    boolean removeFiles, long replaySeqId) throws IOException {</span>
-<span class="source-line-no">5806</span><span id="line-5806">    try {</span>
-<span class="source-line-no">5807</span><span id="line-5807">      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),</span>
-<span class="source-line-no">5808</span><span id="line-5808">        "Compaction marker from WAL ", compaction);</span>
-<span class="source-line-no">5809</span><span id="line-5809">    } catch (WrongRegionException wre) {</span>
-<span class="source-line-no">5810</span><span id="line-5810">      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
-<span class="source-line-no">5811</span><span id="line-5811">        // skip the compaction marker since it is not for this region</span>
-<span class="source-line-no">5812</span><span id="line-5812">        return;</span>
-<span class="source-line-no">5813</span><span id="line-5813">      }</span>
-<span class="source-line-no">5814</span><span id="line-5814">      throw wre;</span>
-<span class="source-line-no">5815</span><span id="line-5815">    }</span>
-<span class="source-line-no">5816</span><span id="line-5816"></span>
-<span class="source-line-no">5817</span><span id="line-5817">    synchronized (writestate) {</span>
-<span class="source-line-no">5818</span><span id="line-5818">      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {</span>
-<span class="source-line-no">5819</span><span id="line-5819">        LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying compaction event :"</span>
-<span class="source-line-no">5820</span><span id="line-5820">          + TextFormat.shortDebugString(compaction) + " because its sequence id " + replaySeqId</span>
-<span class="source-line-no">5821</span><span id="line-5821">          + " is smaller than this regions " + "lastReplayedOpenRegionSeqId of "</span>
-<span class="source-line-no">5822</span><span id="line-5822">          + lastReplayedOpenRegionSeqId);</span>
-<span class="source-line-no">5823</span><span id="line-5823">        return;</span>
-<span class="source-line-no">5824</span><span id="line-5824">      }</span>
-<span class="source-line-no">5825</span><span id="line-5825">      if (replaySeqId &lt; lastReplayedCompactionSeqId) {</span>
-<span class="source-line-no">5826</span><span id="line-5826">        LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying compaction event :"</span>
-<span class="source-line-no">5827</span><span id="line-5827">          + TextFormat.shortDebugString(compaction) + " because its sequence id " + replaySeqId</span>
-<span class="source-line-no">5828</span><span id="line-5828">          + " is smaller than this regions " + "lastReplayedCompactionSeqId of "</span>
-<span class="source-line-no">5829</span><span id="line-5829">          + lastReplayedCompactionSeqId);</span>
-<span class="source-line-no">5830</span><span id="line-5830">        return;</span>
-<span class="source-line-no">5831</span><span id="line-5831">      } else {</span>
-<span class="source-line-no">5832</span><span id="line-5832">        lastReplayedCompactionSeqId = replaySeqId;</span>
-<span class="source-line-no">5833</span><span id="line-5833">      }</span>
-<span class="source-line-no">5834</span><span id="line-5834"></span>
-<span class="source-line-no">5835</span><span id="line-5835">      if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">5836</span><span id="line-5836">        LOG.debug(getRegionInfo().getEncodedName() + " : " + "Replaying compaction marker "</span>
-<span class="source-line-no">5837</span><span id="line-5837">          + TextFormat.shortDebugString(compaction) + " with seqId=" + replaySeqId</span>
-<span class="source-line-no">5838</span><span id="line-5838">          + " and lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);</span>
-<span class="source-line-no">5839</span><span id="line-5839">      }</span>
-<span class="source-line-no">5840</span><span id="line-5840"></span>
-<span class="source-line-no">5841</span><span id="line-5841">      startRegionOperation(Operation.REPLAY_EVENT);</span>
-<span class="source-line-no">5842</span><span id="line-5842">      try {</span>
-<span class="source-line-no">5843</span><span id="line-5843">        HStore store = this.getStore(compaction.getFamilyName().toByteArray());</span>
-<span class="source-line-no">5844</span><span id="line-5844">        if (store == null) {</span>
-<span class="source-line-no">5845</span><span id="line-5845">          LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">5846</span><span id="line-5846">            + "Found Compaction WAL edit for deleted family:"</span>
-<span class="source-line-no">5847</span><span id="line-5847">            + Bytes.toString(compaction.getFamilyName().toByteArray()));</span>
-<span class="source-line-no">5848</span><span id="line-5848">          return;</span>
-<span class="source-line-no">5849</span><span id="line-5849">        }</span>
-<span class="source-line-no">5850</span><span id="line-5850">        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);</span>
-<span class="source-line-no">5851</span><span id="line-5851">        logRegionFiles();</span>
-<span class="source-line-no">5852</span><span id="line-5852">      } catch (FileNotFoundException ex) {</span>
-<span class="source-line-no">5853</span><span id="line-5853">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">5854</span><span id="line-5854">          + "At least one of the store files in compaction: "</span>
-<span class="source-line-no">5855</span><span id="line-5855">          + TextFormat.shortDebugString(compaction)</span>
-<span class="source-line-no">5856</span><span id="line-5856">          + " doesn't exist any more. Skip loading the file(s)", ex);</span>
-<span class="source-line-no">5857</span><span id="line-5857">      } finally {</span>
-<span class="source-line-no">5858</span><span id="line-5858">        closeRegionOperation(Operation.REPLAY_EVENT);</span>
-<span class="source-line-no">5859</span><span id="line-5859">      }</span>
+<span class="source-line-no">5754</span><span id="line-5754"></span>
+<span class="source-line-no">5755</span><span id="line-5755">          boolean flush = false;</span>
+<span class="source-line-no">5756</span><span id="line-5756">          MemStoreSizing memStoreSizing = new NonThreadSafeMemStoreSizing();</span>
+<span class="source-line-no">5757</span><span id="line-5757">          for (Cell c : val.getCells()) {</span>
+<span class="source-line-no">5758</span><span id="line-5758">            assert c instanceof ExtendedCell;</span>
+<span class="source-line-no">5759</span><span id="line-5759">            ExtendedCell cell = (ExtendedCell) c;</span>
+<span class="source-line-no">5760</span><span id="line-5760">            // Check this edit is for me. Also, guard against writing the special</span>
+<span class="source-line-no">5761</span><span id="line-5761">            // METACOLUMN info such as HBASE::CACHEFLUSH entries</span>
+<span class="source-line-no">5762</span><span id="line-5762">            if (WALEdit.isMetaEditFamily(cell)) {</span>
+<span class="source-line-no">5763</span><span id="line-5763">              // if region names don't match, skipp replaying compaction marker</span>
+<span class="source-line-no">5764</span><span id="line-5764">              if (!checkRowWithinBoundary) {</span>
+<span class="source-line-no">5765</span><span id="line-5765">                // this is a special edit, we should handle it</span>
+<span class="source-line-no">5766</span><span id="line-5766">                CompactionDescriptor compaction = WALEdit.getCompaction(cell);</span>
+<span class="source-line-no">5767</span><span id="line-5767">                if (compaction != null) {</span>
+<span class="source-line-no">5768</span><span id="line-5768">                  // replay the compaction</span>
+<span class="source-line-no">5769</span><span id="line-5769">                  replayWALCompactionMarker(compaction, false, true, Long.MAX_VALUE);</span>
+<span class="source-line-no">5770</span><span id="line-5770">                }</span>
+<span class="source-line-no">5771</span><span id="line-5771">              }</span>
+<span class="source-line-no">5772</span><span id="line-5772">              skippedEdits++;</span>
+<span class="source-line-no">5773</span><span id="line-5773">              continue;</span>
+<span class="source-line-no">5774</span><span id="line-5774">            }</span>
+<span class="source-line-no">5775</span><span id="line-5775">            // Figure which store the edit is meant for.</span>
+<span class="source-line-no">5776</span><span id="line-5776">            if (</span>
+<span class="source-line-no">5777</span><span id="line-5777">              store == null</span>
+<span class="source-line-no">5778</span><span id="line-5778">                || !CellUtil.matchingFamily(cell, store.getColumnFamilyDescriptor().getName())</span>
+<span class="source-line-no">5779</span><span id="line-5779">            ) {</span>
+<span class="source-line-no">5780</span><span id="line-5780">              store = getStore(cell);</span>
+<span class="source-line-no">5781</span><span id="line-5781">            }</span>
+<span class="source-line-no">5782</span><span id="line-5782">            if (store == null) {</span>
+<span class="source-line-no">5783</span><span id="line-5783">              // This should never happen. Perhaps schema was changed between</span>
+<span class="source-line-no">5784</span><span id="line-5784">              // crash and redeploy?</span>
+<span class="source-line-no">5785</span><span id="line-5785">              LOG.warn("No family for cell {} in region {}", cell, this);</span>
+<span class="source-line-no">5786</span><span id="line-5786">              skippedEdits++;</span>
+<span class="source-line-no">5787</span><span id="line-5787">              continue;</span>
+<span class="source-line-no">5788</span><span id="line-5788">            }</span>
+<span class="source-line-no">5789</span><span id="line-5789">            if (</span>
+<span class="source-line-no">5790</span><span id="line-5790">              checkRowWithinBoundary &amp;&amp; !rowIsInRange(this.getRegionInfo(), cell.getRowArray(),</span>
+<span class="source-line-no">5791</span><span id="line-5791">                cell.getRowOffset(), cell.getRowLength())</span>
+<span class="source-line-no">5792</span><span id="line-5792">            ) {</span>
+<span class="source-line-no">5793</span><span id="line-5793">              LOG.warn("Row of {} is not within region boundary for region {}", cell, this);</span>
+<span class="source-line-no">5794</span><span id="line-5794">              skippedEdits++;</span>
+<span class="source-line-no">5795</span><span id="line-5795">              continue;</span>
+<span class="source-line-no">5796</span><span id="line-5796">            }</span>
+<span class="source-line-no">5797</span><span id="line-5797">            // Now, figure if we should skip this edit.</span>
+<span class="source-line-no">5798</span><span id="line-5798">            if (</span>
+<span class="source-line-no">5799</span><span id="line-5799">              key.getSequenceId()</span>
+<span class="source-line-no">5800</span><span id="line-5800">                  &lt;= maxSeqIdInStores.get(store.getColumnFamilyDescriptor().getName())</span>
+<span class="source-line-no">5801</span><span id="line-5801">            ) {</span>
+<span class="source-line-no">5802</span><span id="line-5802">              skippedEdits++;</span>
+<span class="source-line-no">5803</span><span id="line-5803">              continue;</span>
+<span class="source-line-no">5804</span><span id="line-5804">            }</span>
+<span class="source-line-no">5805</span><span id="line-5805">            PrivateCellUtil.setSequenceId(cell, currentReplaySeqId);</span>
+<span class="source-line-no">5806</span><span id="line-5806"></span>
+<span class="source-line-no">5807</span><span id="line-5807">            restoreEdit(store, cell, memStoreSizing);</span>
+<span class="source-line-no">5808</span><span id="line-5808">            editsCount++;</span>
+<span class="source-line-no">5809</span><span id="line-5809">          }</span>
+<span class="source-line-no">5810</span><span id="line-5810">          MemStoreSize mss = memStoreSizing.getMemStoreSize();</span>
+<span class="source-line-no">5811</span><span id="line-5811">          incMemStoreSize(mss);</span>
+<span class="source-line-no">5812</span><span id="line-5812">          flush = isFlushSize(this.memStoreSizing.getMemStoreSize());</span>
+<span class="source-line-no">5813</span><span id="line-5813">          if (flush) {</span>
+<span class="source-line-no">5814</span><span id="line-5814">            internalFlushcache(null, currentEditSeqId, stores.values(), status, false,</span>
+<span class="source-line-no">5815</span><span id="line-5815">              FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">5816</span><span id="line-5816">          }</span>
+<span class="source-line-no">5817</span><span id="line-5817">        }</span>
+<span class="source-line-no">5818</span><span id="line-5818"></span>
+<span class="source-line-no">5819</span><span id="line-5819">        if (coprocessorHost != null) {</span>
+<span class="source-line-no">5820</span><span id="line-5820">          coprocessorHost.postReplayWALs(this.getRegionInfo(), edits);</span>
+<span class="source-line-no">5821</span><span id="line-5821">        }</span>
+<span class="source-line-no">5822</span><span id="line-5822">      } catch (EOFException eof) {</span>
+<span class="source-line-no">5823</span><span id="line-5823">        if (!conf.getBoolean(RECOVERED_EDITS_IGNORE_EOF, false)) {</span>
+<span class="source-line-no">5824</span><span id="line-5824">          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);</span>
+<span class="source-line-no">5825</span><span id="line-5825">          msg = "EnLongAddered EOF. Most likely due to Master failure during "</span>
+<span class="source-line-no">5826</span><span id="line-5826">            + "wal splitting, so we have this data in another edit. Continuing, but renaming "</span>
+<span class="source-line-no">5827</span><span id="line-5827">            + edits + " as " + p + " for region " + this;</span>
+<span class="source-line-no">5828</span><span id="line-5828">          LOG.warn(msg, eof);</span>
+<span class="source-line-no">5829</span><span id="line-5829">          status.abort(msg);</span>
+<span class="source-line-no">5830</span><span id="line-5830">        } else {</span>
+<span class="source-line-no">5831</span><span id="line-5831">          LOG.warn("EOF while replaying recover edits and config '{}' is true so "</span>
+<span class="source-line-no">5832</span><span id="line-5832">            + "we will ignore it and continue", RECOVERED_EDITS_IGNORE_EOF, eof);</span>
+<span class="source-line-no">5833</span><span id="line-5833">        }</span>
+<span class="source-line-no">5834</span><span id="line-5834">      } catch (IOException ioe) {</span>
+<span class="source-line-no">5835</span><span id="line-5835">        // If the IOE resulted from bad file format,</span>
+<span class="source-line-no">5836</span><span id="line-5836">        // then this problem is idempotent and retrying won't help</span>
+<span class="source-line-no">5837</span><span id="line-5837">        if (ioe.getCause() instanceof ParseException) {</span>
+<span class="source-line-no">5838</span><span id="line-5838">          Path p = WALSplitUtil.moveAsideBadEditsFile(walFS, edits);</span>
+<span class="source-line-no">5839</span><span id="line-5839">          msg =</span>
+<span class="source-line-no">5840</span><span id="line-5840">            "File corruption enLongAddered!  " + "Continuing, but renaming " + edits + " as " + p;</span>
+<span class="source-line-no">5841</span><span id="line-5841">          LOG.warn(msg, ioe);</span>
+<span class="source-line-no">5842</span><span id="line-5842">          status.setStatus(msg);</span>
+<span class="source-line-no">5843</span><span id="line-5843">        } else {</span>
+<span class="source-line-no">5844</span><span id="line-5844">          status.abort(StringUtils.stringifyException(ioe));</span>
+<span class="source-line-no">5845</span><span id="line-5845">          // other IO errors may be transient (bad network connection,</span>
+<span class="source-line-no">5846</span><span id="line-5846">          // checksum exception on one datanode, etc). throw &amp; retry</span>
+<span class="source-line-no">5847</span><span id="line-5847">          throw ioe;</span>
+<span class="source-line-no">5848</span><span id="line-5848">        }</span>
+<span class="source-line-no">5849</span><span id="line-5849">      }</span>
+<span class="source-line-no">5850</span><span id="line-5850">      if (reporter != null &amp;&amp; !reported_once) {</span>
+<span class="source-line-no">5851</span><span id="line-5851">        reporter.progress();</span>
+<span class="source-line-no">5852</span><span id="line-5852">      }</span>
+<span class="source-line-no">5853</span><span id="line-5853">      msg = "Applied " + editsCount + ", skipped " + skippedEdits + ", firstSequenceIdInLog="</span>
+<span class="source-line-no">5854</span><span id="line-5854">        + firstSeqIdInLog + ", maxSequenceIdInLog=" + currentEditSeqId + ", path=" + edits;</span>
+<span class="source-line-no">5855</span><span id="line-5855">      status.markComplete(msg);</span>
+<span class="source-line-no">5856</span><span id="line-5856">      LOG.debug(msg);</span>
+<span class="source-line-no">5857</span><span id="line-5857">      return currentEditSeqId;</span>
+<span class="source-line-no">5858</span><span id="line-5858">    } finally {</span>
+<span class="source-line-no">5859</span><span id="line-5859">      status.cleanup();</span>
 <span class="source-line-no">5860</span><span id="line-5860">    }</span>
 <span class="source-line-no">5861</span><span id="line-5861">  }</span>
 <span class="source-line-no">5862</span><span id="line-5862"></span>
 <span class="source-line-no">5863</span><span id="line-5863">  /**</span>
-<span class="source-line-no">5864</span><span id="line-5864">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
-<span class="source-line-no">5865</span><span id="line-5865">   *             replica implementation.</span>
+<span class="source-line-no">5864</span><span id="line-5864">   * Call to complete a compaction. Its for the case where we find in the WAL a compaction that was</span>
+<span class="source-line-no">5865</span><span id="line-5865">   * not finished. We could find one recovering a WAL after a regionserver crash. See HBASE-2331.</span>
 <span class="source-line-no">5866</span><span id="line-5866">   */</span>
-<span class="source-line-no">5867</span><span id="line-5867">  @Deprecated</span>
-<span class="source-line-no">5868</span><span id="line-5868">  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {</span>
-<span class="source-line-no">5869</span><span id="line-5869">    checkTargetRegion(flush.getEncodedRegionName().toByteArray(), "Flush marker from WAL ", flush);</span>
-<span class="source-line-no">5870</span><span id="line-5870"></span>
-<span class="source-line-no">5871</span><span id="line-5871">    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
-<span class="source-line-no">5872</span><span id="line-5872">      return; // if primary nothing to do</span>
-<span class="source-line-no">5873</span><span id="line-5873">    }</span>
-<span class="source-line-no">5874</span><span id="line-5874"></span>
-<span class="source-line-no">5875</span><span id="line-5875">    if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">5876</span><span id="line-5876">      LOG.debug(getRegionInfo().getEncodedName() + " : " + "Replaying flush marker "</span>
-<span class="source-line-no">5877</span><span id="line-5877">        + TextFormat.shortDebugString(flush));</span>
+<span class="source-line-no">5867</span><span id="line-5867">  void replayWALCompactionMarker(CompactionDescriptor compaction, boolean pickCompactionFiles,</span>
+<span class="source-line-no">5868</span><span id="line-5868">    boolean removeFiles, long replaySeqId) throws IOException {</span>
+<span class="source-line-no">5869</span><span id="line-5869">    try {</span>
+<span class="source-line-no">5870</span><span id="line-5870">      checkTargetRegion(compaction.getEncodedRegionName().toByteArray(),</span>
+<span class="source-line-no">5871</span><span id="line-5871">        "Compaction marker from WAL ", compaction);</span>
+<span class="source-line-no">5872</span><span id="line-5872">    } catch (WrongRegionException wre) {</span>
+<span class="source-line-no">5873</span><span id="line-5873">      if (RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
+<span class="source-line-no">5874</span><span id="line-5874">        // skip the compaction marker since it is not for this region</span>
+<span class="source-line-no">5875</span><span id="line-5875">        return;</span>
+<span class="source-line-no">5876</span><span id="line-5876">      }</span>
+<span class="source-line-no">5877</span><span id="line-5877">      throw wre;</span>
 <span class="source-line-no">5878</span><span id="line-5878">    }</span>
 <span class="source-line-no">5879</span><span id="line-5879"></span>
-<span class="source-line-no">5880</span><span id="line-5880">    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close</span>
-<span class="source-line-no">5881</span><span id="line-5881">    try {</span>
-<span class="source-line-no">5882</span><span id="line-5882">      FlushAction action = flush.getAction();</span>
-<span class="source-line-no">5883</span><span id="line-5883">      switch (action) {</span>
-<span class="source-line-no">5884</span><span id="line-5884">        case START_FLUSH:</span>
-<span class="source-line-no">5885</span><span id="line-5885">          replayWALFlushStartMarker(flush);</span>
-<span class="source-line-no">5886</span><span id="line-5886">          break;</span>
-<span class="source-line-no">5887</span><span id="line-5887">        case COMMIT_FLUSH:</span>
-<span class="source-line-no">5888</span><span id="line-5888">          replayWALFlushCommitMarker(flush);</span>
-<span class="source-line-no">5889</span><span id="line-5889">          break;</span>
-<span class="source-line-no">5890</span><span id="line-5890">        case ABORT_FLUSH:</span>
-<span class="source-line-no">5891</span><span id="line-5891">          replayWALFlushAbortMarker(flush);</span>
-<span class="source-line-no">5892</span><span id="line-5892">          break;</span>
-<span class="source-line-no">5893</span><span id="line-5893">        case CANNOT_FLUSH:</span>
-<span class="source-line-no">5894</span><span id="line-5894">          replayWALFlushCannotFlushMarker(flush, replaySeqId);</span>
-<span class="source-line-no">5895</span><span id="line-5895">          break;</span>
-<span class="source-line-no">5896</span><span id="line-5896">        default:</span>
-<span class="source-line-no">5897</span><span id="line-5897">          LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">5898</span><span id="line-5898">            + "Received a flush event with unknown action, ignoring. "</span>
-<span class="source-line-no">5899</span><span id="line-5899">            + TextFormat.shortDebugString(flush));</span>
-<span class="source-line-no">5900</span><span id="line-5900">          break;</span>
-<span class="source-line-no">5901</span><span id="line-5901">      }</span>
-<span class="source-line-no">5902</span><span id="line-5902"></span>
-<span class="source-line-no">5903</span><span id="line-5903">      logRegionFiles();</span>
-<span class="source-line-no">5904</span><span id="line-5904">    } finally {</span>
-<span class="source-line-no">5905</span><span id="line-5905">      closeRegionOperation(Operation.REPLAY_EVENT);</span>
-<span class="source-line-no">5906</span><span id="line-5906">    }</span>
-<span class="source-line-no">5907</span><span id="line-5907">  }</span>
-<span class="source-line-no">5908</span><span id="line-5908"></span>
-<span class="source-line-no">5909</span><span id="line-5909">  private Collection&lt;HStore&gt; getStoresToFlush(FlushDescriptor flushDesc) {</span>
-<span class="source-line-no">5910</span><span id="line-5910">    List&lt;HStore&gt; storesToFlush = new ArrayList&lt;&gt;();</span>
-<span class="source-line-no">5911</span><span id="line-5911">    for (StoreFlushDescriptor storeFlush : flushDesc.getStoreFlushesList()) {</span>
-<span class="source-line-no">5912</span><span id="line-5912">      byte[] family = storeFlush.getFamilyName().toByteArray();</span>
-<span class="source-line-no">5913</span><span id="line-5913">      HStore store = getStore(family);</span>
-<span class="source-line-no">5914</span><span id="line-5914">      if (store == null) {</span>
-<span class="source-line-no">5915</span><span id="line-5915">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">5916</span><span id="line-5916">          + "Received a flush start marker from primary, but the family is not found. Ignoring"</span>
-<span class="source-line-no">5917</span><span id="line-5917">          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));</span>
-<span class="source-line-no">5918</span><span id="line-5918">        continue;</span>
-<span class="source-line-no">5919</span><span id="line-5919">      }</span>
-<span class="source-line-no">5920</span><span id="line-5920">      storesToFlush.add(store);</span>
-<span class="source-line-no">5921</span><span id="line-5921">    }</span>
-<span class="source-line-no">5922</span><span id="line-5922">    return storesToFlush;</span>
-<span class="source-line-no">5923</span><span id="line-5923">  }</span>
-<span class="source-line-no">5924</span><span id="line-5924"></span>
-<span class="source-line-no">5925</span><span id="line-5925">  /**</span>
-<span class="source-line-no">5926</span><span id="line-5926">   * Replay the flush marker from primary region by creating a corresponding snapshot of the store</span>
-<span class="source-line-no">5927</span><span id="line-5927">   * memstores, only if the memstores do not have a higher seqId from an earlier wal edit (because</span>
-<span class="source-line-no">5928</span><span id="line-5928">   * the events may be coming out of order).</span>
-<span class="source-line-no">5929</span><span id="line-5929">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
-<span class="source-line-no">5930</span><span id="line-5930">   *             replica implementation.</span>
-<span class="source-line-no">5931</span><span id="line-5931">   */</span>
-<span class="source-line-no">5932</span><span id="line-5932">  @Deprecated</span>
-<span class="source-line-no">5933</span><span id="line-5933">  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {</span>
-<span class="source-line-no">5934</span><span id="line-5934">    long flushSeqId = flush.getFlushSequenceNumber();</span>
-<span class="source-line-no">5935</span><span id="line-5935"></span>
-<span class="source-line-no">5936</span><span id="line-5936">    Collection&lt;HStore&gt; storesToFlush = getStoresToFlush(flush);</span>
+<span class="source-line-no">5880</span><span id="line-5880">    synchronized (writestate) {</span>
+<span class="source-line-no">5881</span><span id="line-5881">      if (replaySeqId &lt; lastReplayedOpenRegionSeqId) {</span>
+<span class="source-line-no">5882</span><span id="line-5882">        LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying compaction event :"</span>
+<span class="source-line-no">5883</span><span id="line-5883">          + TextFormat.shortDebugString(compaction) + " because its sequence id " + replaySeqId</span>
+<span class="source-line-no">5884</span><span id="line-5884">          + " is smaller than this regions " + "lastReplayedOpenRegionSeqId of "</span>
+<span class="source-line-no">5885</span><span id="line-5885">          + lastReplayedOpenRegionSeqId);</span>
+<span class="source-line-no">5886</span><span id="line-5886">        return;</span>
+<span class="source-line-no">5887</span><span id="line-5887">      }</span>
+<span class="source-line-no">5888</span><span id="line-5888">      if (replaySeqId &lt; lastReplayedCompactionSeqId) {</span>
+<span class="source-line-no">5889</span><span id="line-5889">        LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying compaction event :"</span>
+<span class="source-line-no">5890</span><span id="line-5890">          + TextFormat.shortDebugString(compaction) + " because its sequence id " + replaySeqId</span>
+<span class="source-line-no">5891</span><span id="line-5891">          + " is smaller than this regions " + "lastReplayedCompactionSeqId of "</span>
+<span class="source-line-no">5892</span><span id="line-5892">          + lastReplayedCompactionSeqId);</span>
+<span class="source-line-no">5893</span><span id="line-5893">        return;</span>
+<span class="source-line-no">5894</span><span id="line-5894">      } else {</span>
+<span class="source-line-no">5895</span><span id="line-5895">        lastReplayedCompactionSeqId = replaySeqId;</span>
+<span class="source-line-no">5896</span><span id="line-5896">      }</span>
+<span class="source-line-no">5897</span><span id="line-5897"></span>
+<span class="source-line-no">5898</span><span id="line-5898">      if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">5899</span><span id="line-5899">        LOG.debug(getRegionInfo().getEncodedName() + " : " + "Replaying compaction marker "</span>
+<span class="source-line-no">5900</span><span id="line-5900">          + TextFormat.shortDebugString(compaction) + " with seqId=" + replaySeqId</span>
+<span class="source-line-no">5901</span><span id="line-5901">          + " and lastReplayedOpenRegionSeqId=" + lastReplayedOpenRegionSeqId);</span>
+<span class="source-line-no">5902</span><span id="line-5902">      }</span>
+<span class="source-line-no">5903</span><span id="line-5903"></span>
+<span class="source-line-no">5904</span><span id="line-5904">      startRegionOperation(Operation.REPLAY_EVENT);</span>
+<span class="source-line-no">5905</span><span id="line-5905">      try {</span>
+<span class="source-line-no">5906</span><span id="line-5906">        HStore store = this.getStore(compaction.getFamilyName().toByteArray());</span>
+<span class="source-line-no">5907</span><span id="line-5907">        if (store == null) {</span>
+<span class="source-line-no">5908</span><span id="line-5908">          LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">5909</span><span id="line-5909">            + "Found Compaction WAL edit for deleted family:"</span>
+<span class="source-line-no">5910</span><span id="line-5910">            + Bytes.toString(compaction.getFamilyName().toByteArray()));</span>
+<span class="source-line-no">5911</span><span id="line-5911">          return;</span>
+<span class="source-line-no">5912</span><span id="line-5912">        }</span>
+<span class="source-line-no">5913</span><span id="line-5913">        store.replayCompactionMarker(compaction, pickCompactionFiles, removeFiles);</span>
+<span class="source-line-no">5914</span><span id="line-5914">        logRegionFiles();</span>
+<span class="source-line-no">5915</span><span id="line-5915">      } catch (FileNotFoundException ex) {</span>
+<span class="source-line-no">5916</span><span id="line-5916">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">5917</span><span id="line-5917">          + "At least one of the store files in compaction: "</span>
+<span class="source-line-no">5918</span><span id="line-5918">          + TextFormat.shortDebugString(compaction)</span>
+<span class="source-line-no">5919</span><span id="line-5919">          + " doesn't exist any more. Skip loading the file(s)", ex);</span>
+<span class="source-line-no">5920</span><span id="line-5920">      } finally {</span>
+<span class="source-line-no">5921</span><span id="line-5921">        closeRegionOperation(Operation.REPLAY_EVENT);</span>
+<span class="source-line-no">5922</span><span id="line-5922">      }</span>
+<span class="source-line-no">5923</span><span id="line-5923">    }</span>
+<span class="source-line-no">5924</span><span id="line-5924">  }</span>
+<span class="source-line-no">5925</span><span id="line-5925"></span>
+<span class="source-line-no">5926</span><span id="line-5926">  /**</span>
+<span class="source-line-no">5927</span><span id="line-5927">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
+<span class="source-line-no">5928</span><span id="line-5928">   *             replica implementation.</span>
+<span class="source-line-no">5929</span><span id="line-5929">   */</span>
+<span class="source-line-no">5930</span><span id="line-5930">  @Deprecated</span>
+<span class="source-line-no">5931</span><span id="line-5931">  void replayWALFlushMarker(FlushDescriptor flush, long replaySeqId) throws IOException {</span>
+<span class="source-line-no">5932</span><span id="line-5932">    checkTargetRegion(flush.getEncodedRegionName().toByteArray(), "Flush marker from WAL ", flush);</span>
+<span class="source-line-no">5933</span><span id="line-5933"></span>
+<span class="source-line-no">5934</span><span id="line-5934">    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
+<span class="source-line-no">5935</span><span id="line-5935">      return; // if primary nothing to do</span>
+<span class="source-line-no">5936</span><span id="line-5936">    }</span>
 <span class="source-line-no">5937</span><span id="line-5937"></span>
-<span class="source-line-no">5938</span><span id="line-5938">    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);</span>
-<span class="source-line-no">5939</span><span id="line-5939"></span>
-<span class="source-line-no">5940</span><span id="line-5940">    // we will use writestate as a coarse-grain lock for all the replay events</span>
-<span class="source-line-no">5941</span><span id="line-5941">    // (flush, compaction, region open etc)</span>
-<span class="source-line-no">5942</span><span id="line-5942">    synchronized (writestate) {</span>
-<span class="source-line-no">5943</span><span id="line-5943">      try {</span>
-<span class="source-line-no">5944</span><span id="line-5944">        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {</span>
-<span class="source-line-no">5945</span><span id="line-5945">          LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying flush event :"</span>
-<span class="source-line-no">5946</span><span id="line-5946">            + TextFormat.shortDebugString(flush)</span>
-<span class="source-line-no">5947</span><span id="line-5947">            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "</span>
-<span class="source-line-no">5948</span><span id="line-5948">            + " of " + lastReplayedOpenRegionSeqId);</span>
-<span class="source-line-no">5949</span><span id="line-5949">          return null;</span>
-<span class="source-line-no">5950</span><span id="line-5950">        }</span>
-<span class="source-line-no">5951</span><span id="line-5951">        if (numMutationsWithoutWAL.sum() &gt; 0) {</span>
-<span class="source-line-no">5952</span><span id="line-5952">          numMutationsWithoutWAL.reset();</span>
-<span class="source-line-no">5953</span><span id="line-5953">          dataInMemoryWithoutWAL.reset();</span>
-<span class="source-line-no">5954</span><span id="line-5954">        }</span>
-<span class="source-line-no">5955</span><span id="line-5955"></span>
-<span class="source-line-no">5956</span><span id="line-5956">        if (!writestate.flushing) {</span>
-<span class="source-line-no">5957</span><span id="line-5957">          // we do not have an active snapshot and corresponding this.prepareResult. This means</span>
-<span class="source-line-no">5958</span><span id="line-5958">          // we can just snapshot our memstores and continue as normal.</span>
-<span class="source-line-no">5959</span><span id="line-5959"></span>
-<span class="source-line-no">5960</span><span id="line-5960">          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal</span>
-<span class="source-line-no">5961</span><span id="line-5961">          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,</span>
-<span class="source-line-no">5962</span><span id="line-5962">            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);</span>
-<span class="source-line-no">5963</span><span id="line-5963">          if (prepareResult.result == null) {</span>
-<span class="source-line-no">5964</span><span id="line-5964">            // save the PrepareFlushResult so that we can use it later from commit flush</span>
-<span class="source-line-no">5965</span><span id="line-5965">            this.writestate.flushing = true;</span>
-<span class="source-line-no">5966</span><span id="line-5966">            this.prepareFlushResult = prepareResult;</span>
-<span class="source-line-no">5967</span><span id="line-5967">            status.markComplete("Flush prepare successful");</span>
-<span class="source-line-no">5968</span><span id="line-5968">            if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">5969</span><span id="line-5969">              LOG.debug(getRegionInfo().getEncodedName() + " : " + " Prepared flush with seqId:"</span>
-<span class="source-line-no">5970</span><span id="line-5970">                + flush.getFlushSequenceNumber());</span>
-<span class="source-line-no">5971</span><span id="line-5971">            }</span>
-<span class="source-line-no">5972</span><span id="line-5972">          } else {</span>
-<span class="source-line-no">5973</span><span id="line-5973">            // special case empty memstore. We will still save the flush result in this case, since</span>
-<span class="source-line-no">5974</span><span id="line-5974">            // our memstore ie empty, but the primary is still flushing</span>
-<span class="source-line-no">5975</span><span id="line-5975">            if (</span>
-<span class="source-line-no">5976</span><span id="line-5976">              prepareResult.getResult().getResult()</span>
-<span class="source-line-no">5977</span><span id="line-5977">                  == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY</span>
-<span class="source-line-no">5978</span><span id="line-5978">            ) {</span>
-<span class="source-line-no">5979</span><span id="line-5979">              this.writestate.flushing = true;</span>
-<span class="source-line-no">5980</span><span id="line-5980">              this.prepareFlushResult = prepareResult;</span>
-<span class="source-line-no">5981</span><span id="line-5981">              if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">5982</span><span id="line-5982">                LOG.debug(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">5983</span><span id="line-5983">                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());</span>
-<span class="source-line-no">5984</span><span id="line-5984">              }</span>
-<span class="source-line-no">5985</span><span id="line-5985">            }</span>
-<span class="source-line-no">5986</span><span id="line-5986">            status.abort("Flush prepare failed with " + prepareResult.result);</span>
-<span class="source-line-no">5987</span><span id="line-5987">            // nothing much to do. prepare flush failed because of some reason.</span>
-<span class="source-line-no">5988</span><span id="line-5988">          }</span>
-<span class="source-line-no">5989</span><span id="line-5989">          return prepareResult;</span>
-<span class="source-line-no">5990</span><span id="line-5990">        } else {</span>
-<span class="source-line-no">5991</span><span id="line-5991">          // we already have an active snapshot.</span>
-<span class="source-line-no">5992</span><span id="line-5992">          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {</span>
-<span class="source-line-no">5993</span><span id="line-5993">            // They define the same flush. Log and continue.</span>
-<span class="source-line-no">5994</span><span id="line-5994">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">5995</span><span id="line-5995">              + "Received a flush prepare marker with the same seqId: "</span>
-<span class="source-line-no">5996</span><span id="line-5996">              + +flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "</span>
-<span class="source-line-no">5997</span><span id="line-5997">              + prepareFlushResult.flushOpSeqId + ". Ignoring");</span>
-<span class="source-line-no">5998</span><span id="line-5998">            // ignore</span>
-<span class="source-line-no">5999</span><span id="line-5999">          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {</span>
-<span class="source-line-no">6000</span><span id="line-6000">            // We received a flush with a smaller seqNum than what we have prepared. We can only</span>
-<span class="source-line-no">6001</span><span id="line-6001">            // ignore this prepare flush request.</span>
-<span class="source-line-no">6002</span><span id="line-6002">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6003</span><span id="line-6003">              + "Received a flush prepare marker with a smaller seqId: "</span>
-<span class="source-line-no">6004</span><span id="line-6004">              + +flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "</span>
-<span class="source-line-no">6005</span><span id="line-6005">              + prepareFlushResult.flushOpSeqId + ". Ignoring");</span>
-<span class="source-line-no">6006</span><span id="line-6006">            // ignore</span>
-<span class="source-line-no">6007</span><span id="line-6007">          } else {</span>
-<span class="source-line-no">6008</span><span id="line-6008">            // We received a flush with a larger seqNum than what we have prepared</span>
-<span class="source-line-no">6009</span><span id="line-6009">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6010</span><span id="line-6010">              + "Received a flush prepare marker with a larger seqId: "</span>
-<span class="source-line-no">6011</span><span id="line-6011">              + +flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "</span>
-<span class="source-line-no">6012</span><span id="line-6012">              + prepareFlushResult.flushOpSeqId + ". Ignoring");</span>
-<span class="source-line-no">6013</span><span id="line-6013">            // We do not have multiple active snapshots in the memstore or a way to merge current</span>
-<span class="source-line-no">6014</span><span id="line-6014">            // memstore snapshot with the contents and resnapshot for now. We cannot take</span>
-<span class="source-line-no">6015</span><span id="line-6015">            // another snapshot and drop the previous one because that will cause temporary</span>
-<span class="source-line-no">6016</span><span id="line-6016">            // data loss in the secondary. So we ignore this for now, deferring the resolution</span>
-<span class="source-line-no">6017</span><span id="line-6017">            // to happen when we see the corresponding flush commit marker. If we have a memstore</span>
-<span class="source-line-no">6018</span><span id="line-6018">            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),</span>
-<span class="source-line-no">6019</span><span id="line-6019">            // when we see flush commit for y, we will drop snapshot for x, and can also drop all</span>
-<span class="source-line-no">6020</span><span id="line-6020">            // the memstore edits if everything in memstore is &lt; y. This is the usual case for</span>
-<span class="source-line-no">6021</span><span id="line-6021">            // RS crash + recovery where we might see consequtive prepare flush wal markers.</span>
-<span class="source-line-no">6022</span><span id="line-6022">            // Otherwise, this will cause more memory to be used in secondary replica until a</span>
-<span class="source-line-no">6023</span><span id="line-6023">            // further prapare + commit flush is seen and replayed.</span>
-<span class="source-line-no">6024</span><span id="line-6024">          }</span>
-<span class="source-line-no">6025</span><span id="line-6025">        }</span>
-<span class="source-line-no">6026</span><span id="line-6026">      } finally {</span>
-<span class="source-line-no">6027</span><span id="line-6027">        status.cleanup();</span>
-<span class="source-line-no">6028</span><span id="line-6028">        writestate.notifyAll();</span>
-<span class="source-line-no">6029</span><span id="line-6029">      }</span>
-<span class="source-line-no">6030</span><span id="line-6030">    }</span>
-<span class="source-line-no">6031</span><span id="line-6031">    return null;</span>
-<span class="source-line-no">6032</span><span id="line-6032">  }</span>
-<span class="source-line-no">6033</span><span id="line-6033"></span>
-<span class="source-line-no">6034</span><span id="line-6034">  /**</span>
-<span class="source-line-no">6035</span><span id="line-6035">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
-<span class="source-line-no">6036</span><span id="line-6036">   *             replica implementation.</span>
-<span class="source-line-no">6037</span><span id="line-6037">   */</span>
-<span class="source-line-no">6038</span><span id="line-6038">  @Deprecated</span>
-<span class="source-line-no">6039</span><span id="line-6039">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",</span>
-<span class="source-line-no">6040</span><span id="line-6040">      justification = "Intentional; post memstore flush")</span>
-<span class="source-line-no">6041</span><span id="line-6041">  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {</span>
-<span class="source-line-no">6042</span><span id="line-6042">    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);</span>
-<span class="source-line-no">6043</span><span id="line-6043"></span>
-<span class="source-line-no">6044</span><span id="line-6044">    // check whether we have the memstore snapshot with the corresponding seqId. Replay to</span>
-<span class="source-line-no">6045</span><span id="line-6045">    // secondary region replicas are in order, except for when the region moves or then the</span>
-<span class="source-line-no">6046</span><span id="line-6046">    // region server crashes. In those cases, we may receive replay requests out of order from</span>
-<span class="source-line-no">6047</span><span id="line-6047">    // the original seqIds.</span>
-<span class="source-line-no">6048</span><span id="line-6048">    synchronized (writestate) {</span>
-<span class="source-line-no">6049</span><span id="line-6049">      try {</span>
-<span class="source-line-no">6050</span><span id="line-6050">        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {</span>
-<span class="source-line-no">6051</span><span id="line-6051">          LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying flush event :"</span>
-<span class="source-line-no">6052</span><span id="line-6052">            + TextFormat.shortDebugString(flush)</span>
-<span class="source-line-no">6053</span><span id="line-6053">            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "</span>
-<span class="source-line-no">6054</span><span id="line-6054">            + " of " + lastReplayedOpenRegionSeqId);</span>
-<span class="source-line-no">6055</span><span id="line-6055">          return;</span>
-<span class="source-line-no">6056</span><span id="line-6056">        }</span>
-<span class="source-line-no">6057</span><span id="line-6057"></span>
-<span class="source-line-no">6058</span><span id="line-6058">        if (writestate.flushing) {</span>
-<span class="source-line-no">6059</span><span id="line-6059">          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;</span>
-<span class="source-line-no">6060</span><span id="line-6060">          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {</span>
-<span class="source-line-no">6061</span><span id="line-6061">            if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">6062</span><span id="line-6062">              LOG.debug(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6063</span><span id="line-6063">                + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()</span>
-<span class="source-line-no">6064</span><span id="line-6064">                + " and a previous prepared snapshot was found");</span>
-<span class="source-line-no">6065</span><span id="line-6065">            }</span>
-<span class="source-line-no">6066</span><span id="line-6066">            // This is the regular case where we received commit flush after prepare flush</span>
-<span class="source-line-no">6067</span><span id="line-6067">            // corresponding to the same seqId.</span>
-<span class="source-line-no">6068</span><span id="line-6068">            replayFlushInStores(flush, prepareFlushResult, true);</span>
-<span class="source-line-no">6069</span><span id="line-6069"></span>
-<span class="source-line-no">6070</span><span id="line-6070">            // Set down the memstore size by amount of flush.</span>
-<span class="source-line-no">6071</span><span id="line-6071">            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());</span>
-<span class="source-line-no">6072</span><span id="line-6072">            this.prepareFlushResult = null;</span>
-<span class="source-line-no">6073</span><span id="line-6073">            writestate.flushing = false;</span>
-<span class="source-line-no">6074</span><span id="line-6074">          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {</span>
-<span class="source-line-no">6075</span><span id="line-6075">            // This should not happen normally. However, lets be safe and guard against these cases</span>
-<span class="source-line-no">6076</span><span id="line-6076">            // we received a flush commit with a smaller seqId than what we have prepared</span>
-<span class="source-line-no">6077</span><span id="line-6077">            // we will pick the flush file up from this commit (if we have not seen it), but we</span>
-<span class="source-line-no">6078</span><span id="line-6078">            // will not drop the memstore</span>
-<span class="source-line-no">6079</span><span id="line-6079">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6080</span><span id="line-6080">              + "Received a flush commit marker with smaller seqId: "</span>
-<span class="source-line-no">6081</span><span id="line-6081">              + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "</span>
-<span class="source-line-no">6082</span><span id="line-6082">              + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"</span>
-<span class="source-line-no">6083</span><span id="line-6083">              + "  prepared memstore snapshot");</span>
-<span class="source-line-no">6084</span><span id="line-6084">            replayFlushInStores(flush, prepareFlushResult, false);</span>
-<span class="source-line-no">6085</span><span id="line-6085"></span>
-<span class="source-line-no">6086</span><span id="line-6086">            // snapshot is not dropped, so memstore sizes should not be decremented</span>
-<span class="source-line-no">6087</span><span id="line-6087">            // we still have the prepared snapshot, flushing should still be true</span>
-<span class="source-line-no">6088</span><span id="line-6088">          } else {</span>
-<span class="source-line-no">6089</span><span id="line-6089">            // This should not happen normally. However, lets be safe and guard against these cases</span>
-<span class="source-line-no">6090</span><span id="line-6090">            // we received a flush commit with a larger seqId than what we have prepared</span>
-<span class="source-line-no">6091</span><span id="line-6091">            // we will pick the flush file for this. We will also obtain the updates lock and</span>
-<span class="source-line-no">6092</span><span id="line-6092">            // look for contents of the memstore to see whether we have edits after this seqId.</span>
-<span class="source-line-no">6093</span><span id="line-6093">            // If not, we will drop all the memstore edits and the snapshot as well.</span>
-<span class="source-line-no">6094</span><span id="line-6094">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6095</span><span id="line-6095">              + "Received a flush commit marker with larger seqId: "</span>
-<span class="source-line-no">6096</span><span id="line-6096">              + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "</span>
-<span class="source-line-no">6097</span><span id="line-6097">              + prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"</span>
-<span class="source-line-no">6098</span><span id="line-6098">              + " memstore snapshot");</span>
-<span class="source-line-no">6099</span><span id="line-6099"></span>
-<span class="source-line-no">6100</span><span id="line-6100">            replayFlushInStores(flush, prepareFlushResult, true);</span>
-<span class="source-line-no">6101</span><span id="line-6101"></span>
-<span class="source-line-no">6102</span><span id="line-6102">            // Set down the memstore size by amount of flush.</span>
-<span class="source-line-no">6103</span><span id="line-6103">            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());</span>
-<span class="source-line-no">6104</span><span id="line-6104"></span>
-<span class="source-line-no">6105</span><span id="line-6105">            // Inspect the memstore contents to see whether the memstore contains only edits</span>
-<span class="source-line-no">6106</span><span id="line-6106">            // with seqId smaller than the flush seqId. If so, we can discard those edits.</span>
-<span class="source-line-no">6107</span><span id="line-6107">            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);</span>
-<span class="source-line-no">6108</span><span id="line-6108"></span>
-<span class="source-line-no">6109</span><span id="line-6109">            this.prepareFlushResult = null;</span>
-<span class="source-line-no">6110</span><span id="line-6110">            writestate.flushing = false;</span>
-<span class="source-line-no">6111</span><span id="line-6111">          }</span>
-<span class="source-line-no">6112</span><span id="line-6112">          // If we were waiting for observing a flush or region opening event for not showing</span>
-<span class="source-line-no">6113</span><span id="line-6113">          // partial data after a secondary region crash, we can allow reads now. We can only make</span>
-<span class="source-line-no">6114</span><span id="line-6114">          // sure that we are not showing partial data (for example skipping some previous edits)</span>
-<span class="source-line-no">6115</span><span id="line-6115">          // until we observe a full flush start and flush commit. So if we were not able to find</span>
-<span class="source-line-no">6116</span><span id="line-6116">          // a previous flush we will not enable reads now.</span>
-<span class="source-line-no">6117</span><span id="line-6117">          this.setReadsEnabled(true);</span>
-<span class="source-line-no">6118</span><span id="line-6118">        } else {</span>
-<span class="source-line-no">6119</span><span id="line-6119">          LOG.warn(</span>
-<span class="source-line-no">6120</span><span id="line-6120">            getRegionInfo().getEncodedName() + " : " + "Received a flush commit marker with seqId:"</span>
-<span class="source-line-no">6121</span><span id="line-6121">              + flush.getFlushSequenceNumber() + ", but no previous prepared snapshot was found");</span>
-<span class="source-line-no">6122</span><span id="line-6122">          // There is no corresponding prepare snapshot from before.</span>
-<span class="source-line-no">6123</span><span id="line-6123">          // We will pick up the new flushed file</span>
-<span class="source-line-no">6124</span><span id="line-6124">          replayFlushInStores(flush, null, false);</span>
-<span class="source-line-no">6125</span><span id="line-6125"></span>
-<span class="source-line-no">6126</span><span id="line-6126">          // Inspect the memstore contents to see whether the memstore contains only edits</span>
-<span class="source-line-no">6127</span><span id="line-6127">          // with seqId smaller than the flush seqId. If so, we can discard those edits.</span>
-<span class="source-line-no">6128</span><span id="line-6128">          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);</span>
-<span class="source-line-no">6129</span><span id="line-6129">        }</span>
-<span class="source-line-no">6130</span><span id="line-6130"></span>
-<span class="source-line-no">6131</span><span id="line-6131">        status.markComplete("Flush commit successful");</span>
+<span class="source-line-no">5938</span><span id="line-5938">    if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">5939</span><span id="line-5939">      LOG.debug(getRegionInfo().getEncodedName() + " : " + "Replaying flush marker "</span>
+<span class="source-line-no">5940</span><span id="line-5940">        + TextFormat.shortDebugString(flush));</span>
+<span class="source-line-no">5941</span><span id="line-5941">    }</span>
+<span class="source-line-no">5942</span><span id="line-5942"></span>
+<span class="source-line-no">5943</span><span id="line-5943">    startRegionOperation(Operation.REPLAY_EVENT); // use region close lock to guard against close</span>
+<span class="source-line-no">5944</span><span id="line-5944">    try {</span>
+<span class="source-line-no">5945</span><span id="line-5945">      FlushAction action = flush.getAction();</span>
+<span class="source-line-no">5946</span><span id="line-5946">      switch (action) {</span>
+<span class="source-line-no">5947</span><span id="line-5947">        case START_FLUSH:</span>
+<span class="source-line-no">5948</span><span id="line-5948">          replayWALFlushStartMarker(flush);</span>
+<span class="source-line-no">5949</span><span id="line-5949">          break;</span>
+<span class="source-line-no">5950</span><span id="line-5950">        case COMMIT_FLUSH:</span>
+<span class="source-line-no">5951</span><span id="line-5951">          replayWALFlushCommitMarker(flush);</span>
+<span class="source-line-no">5952</span><span id="line-5952">          break;</span>
+<span class="source-line-no">5953</span><span id="line-5953">        case ABORT_FLUSH:</span>
+<span class="source-line-no">5954</span><span id="line-5954">          replayWALFlushAbortMarker(flush);</span>
+<span class="source-line-no">5955</span><span id="line-5955">          break;</span>
+<span class="source-line-no">5956</span><span id="line-5956">        case CANNOT_FLUSH:</span>
+<span class="source-line-no">5957</span><span id="line-5957">          replayWALFlushCannotFlushMarker(flush, replaySeqId);</span>
+<span class="source-line-no">5958</span><span id="line-5958">          break;</span>
+<span class="source-line-no">5959</span><span id="line-5959">        default:</span>
+<span class="source-line-no">5960</span><span id="line-5960">          LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">5961</span><span id="line-5961">            + "Received a flush event with unknown action, ignoring. "</span>
+<span class="source-line-no">5962</span><span id="line-5962">            + TextFormat.shortDebugString(flush));</span>
+<span class="source-line-no">5963</span><span id="line-5963">          break;</span>
+<span class="source-line-no">5964</span><span id="line-5964">      }</span>
+<span class="source-line-no">5965</span><span id="line-5965"></span>
+<span class="source-line-no">5966</span><span id="line-5966">      logRegionFiles();</span>
+<span class="source-line-no">5967</span><span id="line-5967">    } finally {</span>
+<span class="source-line-no">5968</span><span id="line-5968">      closeRegionOperation(Operation.REPLAY_EVENT);</span>
+<span class="source-line-no">5969</span><span id="line-5969">    }</span>
+<span class="source-line-no">5970</span><span id="line-5970">  }</span>
+<span class="source-line-no">5971</span><span id="line-5971"></span>
+<span class="source-line-no">5972</span><span id="line-5972">  private Collection&lt;HStore&gt; getStoresToFlush(FlushDescriptor flushDesc) {</span>
+<span class="source-line-no">5973</span><span id="line-5973">    List&lt;HStore&gt; storesToFlush = new ArrayList&lt;&gt;();</span>
+<span class="source-line-no">5974</span><span id="line-5974">    for (StoreFlushDescriptor storeFlush : flushDesc.getStoreFlushesList()) {</span>
+<span class="source-line-no">5975</span><span id="line-5975">      byte[] family = storeFlush.getFamilyName().toByteArray();</span>
+<span class="source-line-no">5976</span><span id="line-5976">      HStore store = getStore(family);</span>
+<span class="source-line-no">5977</span><span id="line-5977">      if (store == null) {</span>
+<span class="source-line-no">5978</span><span id="line-5978">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">5979</span><span id="line-5979">          + "Received a flush start marker from primary, but the family is not found. Ignoring"</span>
+<span class="source-line-no">5980</span><span id="line-5980">          + " StoreFlushDescriptor:" + TextFormat.shortDebugString(storeFlush));</span>
+<span class="source-line-no">5981</span><span id="line-5981">        continue;</span>
+<span class="source-line-no">5982</span><span id="line-5982">      }</span>
+<span class="source-line-no">5983</span><span id="line-5983">      storesToFlush.add(store);</span>
+<span class="source-line-no">5984</span><span id="line-5984">    }</span>
+<span class="source-line-no">5985</span><span id="line-5985">    return storesToFlush;</span>
+<span class="source-line-no">5986</span><span id="line-5986">  }</span>
+<span class="source-line-no">5987</span><span id="line-5987"></span>
+<span class="source-line-no">5988</span><span id="line-5988">  /**</span>
+<span class="source-line-no">5989</span><span id="line-5989">   * Replay the flush marker from primary region by creating a corresponding snapshot of the store</span>
+<span class="source-line-no">5990</span><span id="line-5990">   * memstores, only if the memstores do not have a higher seqId from an earlier wal edit (because</span>
+<span class="source-line-no">5991</span><span id="line-5991">   * the events may be coming out of order).</span>
+<span class="source-line-no">5992</span><span id="line-5992">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
+<span class="source-line-no">5993</span><span id="line-5993">   *             replica implementation.</span>
+<span class="source-line-no">5994</span><span id="line-5994">   */</span>
+<span class="source-line-no">5995</span><span id="line-5995">  @Deprecated</span>
+<span class="source-line-no">5996</span><span id="line-5996">  PrepareFlushResult replayWALFlushStartMarker(FlushDescriptor flush) throws IOException {</span>
+<span class="source-line-no">5997</span><span id="line-5997">    long flushSeqId = flush.getFlushSequenceNumber();</span>
+<span class="source-line-no">5998</span><span id="line-5998"></span>
+<span class="source-line-no">5999</span><span id="line-5999">    Collection&lt;HStore&gt; storesToFlush = getStoresToFlush(flush);</span>
+<span class="source-line-no">6000</span><span id="line-6000"></span>
+<span class="source-line-no">6001</span><span id="line-6001">    MonitoredTask status = TaskMonitor.get().createStatus("Preparing flush " + this);</span>
+<span class="source-line-no">6002</span><span id="line-6002"></span>
+<span class="source-line-no">6003</span><span id="line-6003">    // we will use writestate as a coarse-grain lock for all the replay events</span>
+<span class="source-line-no">6004</span><span id="line-6004">    // (flush, compaction, region open etc)</span>
+<span class="source-line-no">6005</span><span id="line-6005">    synchronized (writestate) {</span>
+<span class="source-line-no">6006</span><span id="line-6006">      try {</span>
+<span class="source-line-no">6007</span><span id="line-6007">        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {</span>
+<span class="source-line-no">6008</span><span id="line-6008">          LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying flush event :"</span>
+<span class="source-line-no">6009</span><span id="line-6009">            + TextFormat.shortDebugString(flush)</span>
+<span class="source-line-no">6010</span><span id="line-6010">            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "</span>
+<span class="source-line-no">6011</span><span id="line-6011">            + " of " + lastReplayedOpenRegionSeqId);</span>
+<span class="source-line-no">6012</span><span id="line-6012">          return null;</span>
+<span class="source-line-no">6013</span><span id="line-6013">        }</span>
+<span class="source-line-no">6014</span><span id="line-6014">        if (numMutationsWithoutWAL.sum() &gt; 0) {</span>
+<span class="source-line-no">6015</span><span id="line-6015">          numMutationsWithoutWAL.reset();</span>
+<span class="source-line-no">6016</span><span id="line-6016">          dataInMemoryWithoutWAL.reset();</span>
+<span class="source-line-no">6017</span><span id="line-6017">        }</span>
+<span class="source-line-no">6018</span><span id="line-6018"></span>
+<span class="source-line-no">6019</span><span id="line-6019">        if (!writestate.flushing) {</span>
+<span class="source-line-no">6020</span><span id="line-6020">          // we do not have an active snapshot and corresponding this.prepareResult. This means</span>
+<span class="source-line-no">6021</span><span id="line-6021">          // we can just snapshot our memstores and continue as normal.</span>
+<span class="source-line-no">6022</span><span id="line-6022"></span>
+<span class="source-line-no">6023</span><span id="line-6023">          // invoke prepareFlushCache. Send null as wal since we do not want the flush events in wal</span>
+<span class="source-line-no">6024</span><span id="line-6024">          PrepareFlushResult prepareResult = internalPrepareFlushCache(null, flushSeqId,</span>
+<span class="source-line-no">6025</span><span id="line-6025">            storesToFlush, status, false, FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">6026</span><span id="line-6026">          if (prepareResult.result == null) {</span>
+<span class="source-line-no">6027</span><span id="line-6027">            // save the PrepareFlushResult so that we can use it later from commit flush</span>
+<span class="source-line-no">6028</span><span id="line-6028">            this.writestate.flushing = true;</span>
+<span class="source-line-no">6029</span><span id="line-6029">            this.prepareFlushResult = prepareResult;</span>
+<span class="source-line-no">6030</span><span id="line-6030">            status.markComplete("Flush prepare successful");</span>
+<span class="source-line-no">6031</span><span id="line-6031">            if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">6032</span><span id="line-6032">              LOG.debug(getRegionInfo().getEncodedName() + " : " + " Prepared flush with seqId:"</span>
+<span class="source-line-no">6033</span><span id="line-6033">                + flush.getFlushSequenceNumber());</span>
+<span class="source-line-no">6034</span><span id="line-6034">            }</span>
+<span class="source-line-no">6035</span><span id="line-6035">          } else {</span>
+<span class="source-line-no">6036</span><span id="line-6036">            // special case empty memstore. We will still save the flush result in this case, since</span>
+<span class="source-line-no">6037</span><span id="line-6037">            // our memstore ie empty, but the primary is still flushing</span>
+<span class="source-line-no">6038</span><span id="line-6038">            if (</span>
+<span class="source-line-no">6039</span><span id="line-6039">              prepareResult.getResult().getResult()</span>
+<span class="source-line-no">6040</span><span id="line-6040">                  == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY</span>
+<span class="source-line-no">6041</span><span id="line-6041">            ) {</span>
+<span class="source-line-no">6042</span><span id="line-6042">              this.writestate.flushing = true;</span>
+<span class="source-line-no">6043</span><span id="line-6043">              this.prepareFlushResult = prepareResult;</span>
+<span class="source-line-no">6044</span><span id="line-6044">              if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">6045</span><span id="line-6045">                LOG.debug(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6046</span><span id="line-6046">                  + " Prepared empty flush with seqId:" + flush.getFlushSequenceNumber());</span>
+<span class="source-line-no">6047</span><span id="line-6047">              }</span>
+<span class="source-line-no">6048</span><span id="line-6048">            }</span>
+<span class="source-line-no">6049</span><span id="line-6049">            status.abort("Flush prepare failed with " + prepareResult.result);</span>
+<span class="source-line-no">6050</span><span id="line-6050">            // nothing much to do. prepare flush failed because of some reason.</span>
+<span class="source-line-no">6051</span><span id="line-6051">          }</span>
+<span class="source-line-no">6052</span><span id="line-6052">          return prepareResult;</span>
+<span class="source-line-no">6053</span><span id="line-6053">        } else {</span>
+<span class="source-line-no">6054</span><span id="line-6054">          // we already have an active snapshot.</span>
+<span class="source-line-no">6055</span><span id="line-6055">          if (flush.getFlushSequenceNumber() == this.prepareFlushResult.flushOpSeqId) {</span>
+<span class="source-line-no">6056</span><span id="line-6056">            // They define the same flush. Log and continue.</span>
+<span class="source-line-no">6057</span><span id="line-6057">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6058</span><span id="line-6058">              + "Received a flush prepare marker with the same seqId: "</span>
+<span class="source-line-no">6059</span><span id="line-6059">              + +flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "</span>
+<span class="source-line-no">6060</span><span id="line-6060">              + prepareFlushResult.flushOpSeqId + ". Ignoring");</span>
+<span class="source-line-no">6061</span><span id="line-6061">            // ignore</span>
+<span class="source-line-no">6062</span><span id="line-6062">          } else if (flush.getFlushSequenceNumber() &lt; this.prepareFlushResult.flushOpSeqId) {</span>
+<span class="source-line-no">6063</span><span id="line-6063">            // We received a flush with a smaller seqNum than what we have prepared. We can only</span>
+<span class="source-line-no">6064</span><span id="line-6064">            // ignore this prepare flush request.</span>
+<span class="source-line-no">6065</span><span id="line-6065">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6066</span><span id="line-6066">              + "Received a flush prepare marker with a smaller seqId: "</span>
+<span class="source-line-no">6067</span><span id="line-6067">              + +flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "</span>
+<span class="source-line-no">6068</span><span id="line-6068">              + prepareFlushResult.flushOpSeqId + ". Ignoring");</span>
+<span class="source-line-no">6069</span><span id="line-6069">            // ignore</span>
+<span class="source-line-no">6070</span><span id="line-6070">          } else {</span>
+<span class="source-line-no">6071</span><span id="line-6071">            // We received a flush with a larger seqNum than what we have prepared</span>
+<span class="source-line-no">6072</span><span id="line-6072">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6073</span><span id="line-6073">              + "Received a flush prepare marker with a larger seqId: "</span>
+<span class="source-line-no">6074</span><span id="line-6074">              + +flush.getFlushSequenceNumber() + " before clearing the previous one with seqId: "</span>
+<span class="source-line-no">6075</span><span id="line-6075">              + prepareFlushResult.flushOpSeqId + ". Ignoring");</span>
+<span class="source-line-no">6076</span><span id="line-6076">            // We do not have multiple active snapshots in the memstore or a way to merge current</span>
+<span class="source-line-no">6077</span><span id="line-6077">            // memstore snapshot with the contents and resnapshot for now. We cannot take</span>
+<span class="source-line-no">6078</span><span id="line-6078">            // another snapshot and drop the previous one because that will cause temporary</span>
+<span class="source-line-no">6079</span><span id="line-6079">            // data loss in the secondary. So we ignore this for now, deferring the resolution</span>
+<span class="source-line-no">6080</span><span id="line-6080">            // to happen when we see the corresponding flush commit marker. If we have a memstore</span>
+<span class="source-line-no">6081</span><span id="line-6081">            // snapshot with x, and later received another prepare snapshot with y (where x &lt; y),</span>
+<span class="source-line-no">6082</span><span id="line-6082">            // when we see flush commit for y, we will drop snapshot for x, and can also drop all</span>
+<span class="source-line-no">6083</span><span id="line-6083">            // the memstore edits if everything in memstore is &lt; y. This is the usual case for</span>
+<span class="source-line-no">6084</span><span id="line-6084">            // RS crash + recovery where we might see consequtive prepare flush wal markers.</span>
+<span class="source-line-no">6085</span><span id="line-6085">            // Otherwise, this will cause more memory to be used in secondary replica until a</span>
+<span class="source-line-no">6086</span><span id="line-6086">            // further prapare + commit flush is seen and replayed.</span>
+<span class="source-line-no">6087</span><span id="line-6087">          }</span>
+<span class="source-line-no">6088</span><span id="line-6088">        }</span>
+<span class="source-line-no">6089</span><span id="line-6089">      } finally {</span>
+<span class="source-line-no">6090</span><span id="line-6090">        status.cleanup();</span>
+<span class="source-line-no">6091</span><span id="line-6091">        writestate.notifyAll();</span>
+<span class="source-line-no">6092</span><span id="line-6092">      }</span>
+<span class="source-line-no">6093</span><span id="line-6093">    }</span>
+<span class="source-line-no">6094</span><span id="line-6094">    return null;</span>
+<span class="source-line-no">6095</span><span id="line-6095">  }</span>
+<span class="source-line-no">6096</span><span id="line-6096"></span>
+<span class="source-line-no">6097</span><span id="line-6097">  /**</span>
+<span class="source-line-no">6098</span><span id="line-6098">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
+<span class="source-line-no">6099</span><span id="line-6099">   *             replica implementation.</span>
+<span class="source-line-no">6100</span><span id="line-6100">   */</span>
+<span class="source-line-no">6101</span><span id="line-6101">  @Deprecated</span>
+<span class="source-line-no">6102</span><span id="line-6102">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",</span>
+<span class="source-line-no">6103</span><span id="line-6103">      justification = "Intentional; post memstore flush")</span>
+<span class="source-line-no">6104</span><span id="line-6104">  void replayWALFlushCommitMarker(FlushDescriptor flush) throws IOException {</span>
+<span class="source-line-no">6105</span><span id="line-6105">    MonitoredTask status = TaskMonitor.get().createStatus("Committing flush " + this);</span>
+<span class="source-line-no">6106</span><span id="line-6106"></span>
+<span class="source-line-no">6107</span><span id="line-6107">    // check whether we have the memstore snapshot with the corresponding seqId. Replay to</span>
+<span class="source-line-no">6108</span><span id="line-6108">    // secondary region replicas are in order, except for when the region moves or then the</span>
+<span class="source-line-no">6109</span><span id="line-6109">    // region server crashes. In those cases, we may receive replay requests out of order from</span>
+<span class="source-line-no">6110</span><span id="line-6110">    // the original seqIds.</span>
+<span class="source-line-no">6111</span><span id="line-6111">    synchronized (writestate) {</span>
+<span class="source-line-no">6112</span><span id="line-6112">      try {</span>
+<span class="source-line-no">6113</span><span id="line-6113">        if (flush.getFlushSequenceNumber() &lt; lastReplayedOpenRegionSeqId) {</span>
+<span class="source-line-no">6114</span><span id="line-6114">          LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying flush event :"</span>
+<span class="source-line-no">6115</span><span id="line-6115">            + TextFormat.shortDebugString(flush)</span>
+<span class="source-line-no">6116</span><span id="line-6116">            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "</span>
+<span class="source-line-no">6117</span><span id="line-6117">            + " of " + lastReplayedOpenRegionSeqId);</span>
+<span class="source-line-no">6118</span><span id="line-6118">          return;</span>
+<span class="source-line-no">6119</span><span id="line-6119">        }</span>
+<span class="source-line-no">6120</span><span id="line-6120"></span>
+<span class="source-line-no">6121</span><span id="line-6121">        if (writestate.flushing) {</span>
+<span class="source-line-no">6122</span><span id="line-6122">          PrepareFlushResult prepareFlushResult = this.prepareFlushResult;</span>
+<span class="source-line-no">6123</span><span id="line-6123">          if (flush.getFlushSequenceNumber() == prepareFlushResult.flushOpSeqId) {</span>
+<span class="source-line-no">6124</span><span id="line-6124">            if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">6125</span><span id="line-6125">              LOG.debug(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6126</span><span id="line-6126">                + "Received a flush commit marker with seqId:" + flush.getFlushSequenceNumber()</span>
+<span class="source-line-no">6127</span><span id="line-6127">                + " and a previous prepared snapshot was found");</span>
+<span class="source-line-no">6128</span><span id="line-6128">            }</span>
+<span class="source-line-no">6129</span><span id="line-6129">            // This is the regular case where we received commit flush after prepare flush</span>
+<span class="source-line-no">6130</span><span id="line-6130">            // corresponding to the same seqId.</span>
+<span class="source-line-no">6131</span><span id="line-6131">            replayFlushInStores(flush, prepareFlushResult, true);</span>
 <span class="source-line-no">6132</span><span id="line-6132"></span>
-<span class="source-line-no">6133</span><span id="line-6133">        // Update the last flushed sequence id for region.</span>
-<span class="source-line-no">6134</span><span id="line-6134">        this.maxFlushedSeqId = flush.getFlushSequenceNumber();</span>
-<span class="source-line-no">6135</span><span id="line-6135"></span>
-<span class="source-line-no">6136</span><span id="line-6136">        // advance the mvcc read point so that the new flushed file is visible.</span>
-<span class="source-line-no">6137</span><span id="line-6137">        mvcc.advanceTo(flush.getFlushSequenceNumber());</span>
-<span class="source-line-no">6138</span><span id="line-6138"></span>
-<span class="source-line-no">6139</span><span id="line-6139">      } catch (FileNotFoundException ex) {</span>
-<span class="source-line-no">6140</span><span id="line-6140">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6141</span><span id="line-6141">          + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)</span>
-<span class="source-line-no">6142</span><span id="line-6142">          + " doesn't exist any more. Skip loading the file(s)", ex);</span>
-<span class="source-line-no">6143</span><span id="line-6143">      } finally {</span>
-<span class="source-line-no">6144</span><span id="line-6144">        status.cleanup();</span>
-<span class="source-line-no">6145</span><span id="line-6145">        writestate.notifyAll();</span>
-<span class="source-line-no">6146</span><span id="line-6146">      }</span>
-<span class="source-line-no">6147</span><span id="line-6147">    }</span>
+<span class="source-line-no">6133</span><span id="line-6133">            // Set down the memstore size by amount of flush.</span>
+<span class="source-line-no">6134</span><span id="line-6134">            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());</span>
+<span class="source-line-no">6135</span><span id="line-6135">            this.prepareFlushResult = null;</span>
+<span class="source-line-no">6136</span><span id="line-6136">            writestate.flushing = false;</span>
+<span class="source-line-no">6137</span><span id="line-6137">          } else if (flush.getFlushSequenceNumber() &lt; prepareFlushResult.flushOpSeqId) {</span>
+<span class="source-line-no">6138</span><span id="line-6138">            // This should not happen normally. However, lets be safe and guard against these cases</span>
+<span class="source-line-no">6139</span><span id="line-6139">            // we received a flush commit with a smaller seqId than what we have prepared</span>
+<span class="source-line-no">6140</span><span id="line-6140">            // we will pick the flush file up from this commit (if we have not seen it), but we</span>
+<span class="source-line-no">6141</span><span id="line-6141">            // will not drop the memstore</span>
+<span class="source-line-no">6142</span><span id="line-6142">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6143</span><span id="line-6143">              + "Received a flush commit marker with smaller seqId: "</span>
+<span class="source-line-no">6144</span><span id="line-6144">              + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "</span>
+<span class="source-line-no">6145</span><span id="line-6145">              + prepareFlushResult.flushOpSeqId + ". Picking up new file, but not dropping"</span>
+<span class="source-line-no">6146</span><span id="line-6146">              + "  prepared memstore snapshot");</span>
+<span class="source-line-no">6147</span><span id="line-6147">            replayFlushInStores(flush, prepareFlushResult, false);</span>
 <span class="source-line-no">6148</span><span id="line-6148"></span>
-<span class="source-line-no">6149</span><span id="line-6149">    // C. Finally notify anyone waiting on memstore to clear:</span>
-<span class="source-line-no">6150</span><span id="line-6150">    // e.g. checkResources().</span>
-<span class="source-line-no">6151</span><span id="line-6151">    synchronized (this) {</span>
-<span class="source-line-no">6152</span><span id="line-6152">      notifyAll(); // FindBugs NN_NAKED_NOTIFY</span>
-<span class="source-line-no">6153</span><span id="line-6153">    }</span>
-<span class="source-line-no">6154</span><span id="line-6154">  }</span>
-<span class="source-line-no">6155</span><span id="line-6155"></span>
-<span class="source-line-no">6156</span><span id="line-6156">  /**</span>
-<span class="source-line-no">6157</span><span id="line-6157">   * Replays the given flush descriptor by opening the flush files in stores and dropping the</span>
-<span class="source-line-no">6158</span><span id="line-6158">   * memstore snapshots if requested.</span>
-<span class="source-line-no">6159</span><span id="line-6159">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
-<span class="source-line-no">6160</span><span id="line-6160">   *             replica implementation.</span>
-<span class="source-line-no">6161</span><span id="line-6161">   */</span>
-<span class="source-line-no">6162</span><span id="line-6162">  @Deprecated</span>
-<span class="source-line-no">6163</span><span id="line-6163">  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,</span>
-<span class="source-line-no">6164</span><span id="line-6164">    boolean dropMemstoreSnapshot) throws IOException {</span>
-<span class="source-line-no">6165</span><span id="line-6165">    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {</span>
-<span class="source-line-no">6166</span><span id="line-6166">      byte[] family = storeFlush.getFamilyName().toByteArray();</span>
-<span class="source-line-no">6167</span><span id="line-6167">      HStore store = getStore(family);</span>
-<span class="source-line-no">6168</span><span id="line-6168">      if (store == null) {</span>
-<span class="source-line-no">6169</span><span id="line-6169">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6170</span><span id="line-6170">          + "Received a flush commit marker from primary, but the family is not found."</span>
-<span class="source-line-no">6171</span><span id="line-6171">          + "Ignoring StoreFlushDescriptor:" + storeFlush);</span>
-<span class="source-line-no">6172</span><span id="line-6172">        continue;</span>
-<span class="source-line-no">6173</span><span id="line-6173">      }</span>
-<span class="source-line-no">6174</span><span id="line-6174">      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();</span>
-<span class="source-line-no">6175</span><span id="line-6175">      StoreFlushContext ctx = null;</span>
-<span class="source-line-no">6176</span><span id="line-6176">      long startTime = EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">6177</span><span id="line-6177">      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {</span>
-<span class="source-line-no">6178</span><span id="line-6178">        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);</span>
-<span class="source-line-no">6179</span><span id="line-6179">      } else {</span>
-<span class="source-line-no">6180</span><span id="line-6180">        ctx = prepareFlushResult.storeFlushCtxs.get(family);</span>
-<span class="source-line-no">6181</span><span id="line-6181">        startTime = prepareFlushResult.startTime;</span>
-<span class="source-line-no">6182</span><span id="line-6182">      }</span>
-<span class="source-line-no">6183</span><span id="line-6183"></span>
-<span class="source-line-no">6184</span><span id="line-6184">      if (ctx == null) {</span>
-<span class="source-line-no">6185</span><span id="line-6185">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6186</span><span id="line-6186">          + "Unexpected: flush commit marker received from store " + Bytes.toString(family)</span>
-<span class="source-line-no">6187</span><span id="line-6187">          + " but no associated flush context. Ignoring");</span>
-<span class="source-line-no">6188</span><span id="line-6188">        continue;</span>
-<span class="source-line-no">6189</span><span id="line-6189">      }</span>
-<span class="source-line-no">6190</span><span id="line-6190"></span>
-<span class="source-line-no">6191</span><span id="line-6191">      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush</span>
-<span class="source-line-no">6192</span><span id="line-6192"></span>
-<span class="source-line-no">6193</span><span id="line-6193">      // Record latest flush time</span>
-<span class="source-line-no">6194</span><span id="line-6194">      this.lastStoreFlushTimeMap.put(store, startTime);</span>
-<span class="source-line-no">6195</span><span id="line-6195">    }</span>
-<span class="source-line-no">6196</span><span id="line-6196">  }</span>
-<span class="source-line-no">6197</span><span id="line-6197"></span>
-<span class="source-line-no">6198</span><span id="line-6198">  private long loadRecoveredHFilesIfAny(Collection&lt;HStore&gt; stores) throws IOException {</span>
-<span class="source-line-no">6199</span><span id="line-6199">    Path regionDir = fs.getRegionDir();</span>
-<span class="source-line-no">6200</span><span id="line-6200">    long maxSeqId = -1;</span>
-<span class="source-line-no">6201</span><span id="line-6201">    for (HStore store : stores) {</span>
-<span class="source-line-no">6202</span><span id="line-6202">      String familyName = store.getColumnFamilyName();</span>
-<span class="source-line-no">6203</span><span id="line-6203">      FileStatus[] files =</span>
-<span class="source-line-no">6204</span><span id="line-6204">        WALSplitUtil.getRecoveredHFiles(fs.getFileSystem(), regionDir, familyName);</span>
-<span class="source-line-no">6205</span><span id="line-6205">      if (files != null &amp;&amp; files.length != 0) {</span>
-<span class="source-line-no">6206</span><span id="line-6206">        for (FileStatus file : files) {</span>
-<span class="source-line-no">6207</span><span id="line-6207">          Path filePath = file.getPath();</span>
-<span class="source-line-no">6208</span><span id="line-6208">          // If file length is zero then delete it</span>
-<span class="source-line-no">6209</span><span id="line-6209">          if (isZeroLengthThenDelete(fs.getFileSystem(), file, filePath)) {</span>
-<span class="source-line-no">6210</span><span id="line-6210">            continue;</span>
-<span class="source-line-no">6211</span><span id="line-6211">          }</span>
-<span class="source-line-no">6212</span><span id="line-6212">          try {</span>
-<span class="source-line-no">6213</span><span id="line-6213">            HStoreFile storefile = store.tryCommitRecoveredHFile(file.getPath());</span>
-<span class="source-line-no">6214</span><span id="line-6214">            maxSeqId = Math.max(maxSeqId, storefile.getReader().getSequenceID());</span>
-<span class="source-line-no">6215</span><span id="line-6215">          } catch (IOException e) {</span>
-<span class="source-line-no">6216</span><span id="line-6216">            handleException(fs.getFileSystem(), filePath, e);</span>
-<span class="source-line-no">6217</span><span id="line-6217">            continue;</span>
-<span class="source-line-no">6218</span><span id="line-6218">          }</span>
-<span class="source-line-no">6219</span><span id="line-6219">        }</span>
-<span class="source-line-no">6220</span><span id="line-6220">        if (this.rsServices != null &amp;&amp; store.needsCompaction()) {</span>
-<span class="source-line-no">6221</span><span id="line-6221">          this.rsServices.getCompactionRequestor().requestCompaction(this, store,</span>
-<span class="source-line-no">6222</span><span id="line-6222">            "load recovered hfiles request compaction", Store.PRIORITY_USER + 1,</span>
-<span class="source-line-no">6223</span><span id="line-6223">            CompactionLifeCycleTracker.DUMMY, null);</span>
-<span class="source-line-no">6224</span><span id="line-6224">        }</span>
-<span class="source-line-no">6225</span><span id="line-6225">      }</span>
-<span class="source-line-no">6226</span><span id="line-6226">    }</span>
-<span class="source-line-no">6227</span><span id="line-6227">    return maxSeqId;</span>
-<span class="source-line-no">6228</span><span id="line-6228">  }</span>
-<span class="source-line-no">6229</span><span id="line-6229"></span>
-<span class="source-line-no">6230</span><span id="line-6230">  /**</span>
-<span class="source-line-no">6231</span><span id="line-6231">   * Be careful, this method will drop all data in the memstore of this region. Currently, this</span>
-<span class="source-line-no">6232</span><span id="line-6232">   * method is used to drop memstore to prevent memory leak when replaying recovered.edits while</span>
-<span class="source-line-no">6233</span><span id="line-6233">   * opening region.</span>
-<span class="source-line-no">6234</span><span id="line-6234">   */</span>
-<span class="source-line-no">6235</span><span id="line-6235">  private MemStoreSize dropMemStoreContents() throws IOException {</span>
-<span class="source-line-no">6236</span><span id="line-6236">    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();</span>
-<span class="source-line-no">6237</span><span id="line-6237">    this.updatesLock.writeLock().lock();</span>
-<span class="source-line-no">6238</span><span id="line-6238">    try {</span>
-<span class="source-line-no">6239</span><span id="line-6239">      for (HStore s : stores.values()) {</span>
-<span class="source-line-no">6240</span><span id="line-6240">        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);</span>
-<span class="source-line-no">6241</span><span id="line-6241">        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "</span>
-<span class="source-line-no">6242</span><span id="line-6242">          + this.getRegionInfo().getRegionNameAsString() + " , dropped memstoresize: ["</span>
-<span class="source-line-no">6243</span><span id="line-6243">          + memStoreSize + " }");</span>
-<span class="source-line-no">6244</span><span id="line-6244">        totalFreedSize.incMemStoreSize(memStoreSize);</span>
+<span class="source-line-no">6149</span><span id="line-6149">            // snapshot is not dropped, so memstore sizes should not be decremented</span>
+<span class="source-line-no">6150</span><span id="line-6150">            // we still have the prepared snapshot, flushing should still be true</span>
+<span class="source-line-no">6151</span><span id="line-6151">          } else {</span>
+<span class="source-line-no">6152</span><span id="line-6152">            // This should not happen normally. However, lets be safe and guard against these cases</span>
+<span class="source-line-no">6153</span><span id="line-6153">            // we received a flush commit with a larger seqId than what we have prepared</span>
+<span class="source-line-no">6154</span><span id="line-6154">            // we will pick the flush file for this. We will also obtain the updates lock and</span>
+<span class="source-line-no">6155</span><span id="line-6155">            // look for contents of the memstore to see whether we have edits after this seqId.</span>
+<span class="source-line-no">6156</span><span id="line-6156">            // If not, we will drop all the memstore edits and the snapshot as well.</span>
+<span class="source-line-no">6157</span><span id="line-6157">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6158</span><span id="line-6158">              + "Received a flush commit marker with larger seqId: "</span>
+<span class="source-line-no">6159</span><span id="line-6159">              + flush.getFlushSequenceNumber() + " than what we have prepared with seqId: "</span>
+<span class="source-line-no">6160</span><span id="line-6160">              + prepareFlushResult.flushOpSeqId + ". Picking up new file and dropping prepared"</span>
+<span class="source-line-no">6161</span><span id="line-6161">              + " memstore snapshot");</span>
+<span class="source-line-no">6162</span><span id="line-6162"></span>
+<span class="source-line-no">6163</span><span id="line-6163">            replayFlushInStores(flush, prepareFlushResult, true);</span>
+<span class="source-line-no">6164</span><span id="line-6164"></span>
+<span class="source-line-no">6165</span><span id="line-6165">            // Set down the memstore size by amount of flush.</span>
+<span class="source-line-no">6166</span><span id="line-6166">            this.decrMemStoreSize(prepareFlushResult.totalFlushableSize.getMemStoreSize());</span>
+<span class="source-line-no">6167</span><span id="line-6167"></span>
+<span class="source-line-no">6168</span><span id="line-6168">            // Inspect the memstore contents to see whether the memstore contains only edits</span>
+<span class="source-line-no">6169</span><span id="line-6169">            // with seqId smaller than the flush seqId. If so, we can discard those edits.</span>
+<span class="source-line-no">6170</span><span id="line-6170">            dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);</span>
+<span class="source-line-no">6171</span><span id="line-6171"></span>
+<span class="source-line-no">6172</span><span id="line-6172">            this.prepareFlushResult = null;</span>
+<span class="source-line-no">6173</span><span id="line-6173">            writestate.flushing = false;</span>
+<span class="source-line-no">6174</span><span id="line-6174">          }</span>
+<span class="source-line-no">6175</span><span id="line-6175">          // If we were waiting for observing a flush or region opening event for not showing</span>
+<span class="source-line-no">6176</span><span id="line-6176">          // partial data after a secondary region crash, we can allow reads now. We can only make</span>
+<span class="source-line-no">6177</span><span id="line-6177">          // sure that we are not showing partial data (for example skipping some previous edits)</span>
+<span class="source-line-no">6178</span><span id="line-6178">          // until we observe a full flush start and flush commit. So if we were not able to find</span>
+<span class="source-line-no">6179</span><span id="line-6179">          // a previous flush we will not enable reads now.</span>
+<span class="source-line-no">6180</span><span id="line-6180">          this.setReadsEnabled(true);</span>
+<span class="source-line-no">6181</span><span id="line-6181">        } else {</span>
+<span class="source-line-no">6182</span><span id="line-6182">          LOG.warn(</span>
+<span class="source-line-no">6183</span><span id="line-6183">            getRegionInfo().getEncodedName() + " : " + "Received a flush commit marker with seqId:"</span>
+<span class="source-line-no">6184</span><span id="line-6184">              + flush.getFlushSequenceNumber() + ", but no previous prepared snapshot was found");</span>
+<span class="source-line-no">6185</span><span id="line-6185">          // There is no corresponding prepare snapshot from before.</span>
+<span class="source-line-no">6186</span><span id="line-6186">          // We will pick up the new flushed file</span>
+<span class="source-line-no">6187</span><span id="line-6187">          replayFlushInStores(flush, null, false);</span>
+<span class="source-line-no">6188</span><span id="line-6188"></span>
+<span class="source-line-no">6189</span><span id="line-6189">          // Inspect the memstore contents to see whether the memstore contains only edits</span>
+<span class="source-line-no">6190</span><span id="line-6190">          // with seqId smaller than the flush seqId. If so, we can discard those edits.</span>
+<span class="source-line-no">6191</span><span id="line-6191">          dropMemStoreContentsForSeqId(flush.getFlushSequenceNumber(), null);</span>
+<span class="source-line-no">6192</span><span id="line-6192">        }</span>
+<span class="source-line-no">6193</span><span id="line-6193"></span>
+<span class="source-line-no">6194</span><span id="line-6194">        status.markComplete("Flush commit successful");</span>
+<span class="source-line-no">6195</span><span id="line-6195"></span>
+<span class="source-line-no">6196</span><span id="line-6196">        // Update the last flushed sequence id for region.</span>
+<span class="source-line-no">6197</span><span id="line-6197">        this.maxFlushedSeqId = flush.getFlushSequenceNumber();</span>
+<span class="source-line-no">6198</span><span id="line-6198"></span>
+<span class="source-line-no">6199</span><span id="line-6199">        // advance the mvcc read point so that the new flushed file is visible.</span>
+<span class="source-line-no">6200</span><span id="line-6200">        mvcc.advanceTo(flush.getFlushSequenceNumber());</span>
+<span class="source-line-no">6201</span><span id="line-6201"></span>
+<span class="source-line-no">6202</span><span id="line-6202">      } catch (FileNotFoundException ex) {</span>
+<span class="source-line-no">6203</span><span id="line-6203">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6204</span><span id="line-6204">          + "At least one of the store files in flush: " + TextFormat.shortDebugString(flush)</span>
+<span class="source-line-no">6205</span><span id="line-6205">          + " doesn't exist any more. Skip loading the file(s)", ex);</span>
+<span class="source-line-no">6206</span><span id="line-6206">      } finally {</span>
+<span class="source-line-no">6207</span><span id="line-6207">        status.cleanup();</span>
+<span class="source-line-no">6208</span><span id="line-6208">        writestate.notifyAll();</span>
+<span class="source-line-no">6209</span><span id="line-6209">      }</span>
+<span class="source-line-no">6210</span><span id="line-6210">    }</span>
+<span class="source-line-no">6211</span><span id="line-6211"></span>
+<span class="source-line-no">6212</span><span id="line-6212">    // C. Finally notify anyone waiting on memstore to clear:</span>
+<span class="source-line-no">6213</span><span id="line-6213">    // e.g. checkResources().</span>
+<span class="source-line-no">6214</span><span id="line-6214">    synchronized (this) {</span>
+<span class="source-line-no">6215</span><span id="line-6215">      notifyAll(); // FindBugs NN_NAKED_NOTIFY</span>
+<span class="source-line-no">6216</span><span id="line-6216">    }</span>
+<span class="source-line-no">6217</span><span id="line-6217">  }</span>
+<span class="source-line-no">6218</span><span id="line-6218"></span>
+<span class="source-line-no">6219</span><span id="line-6219">  /**</span>
+<span class="source-line-no">6220</span><span id="line-6220">   * Replays the given flush descriptor by opening the flush files in stores and dropping the</span>
+<span class="source-line-no">6221</span><span id="line-6221">   * memstore snapshots if requested.</span>
+<span class="source-line-no">6222</span><span id="line-6222">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
+<span class="source-line-no">6223</span><span id="line-6223">   *             replica implementation.</span>
+<span class="source-line-no">6224</span><span id="line-6224">   */</span>
+<span class="source-line-no">6225</span><span id="line-6225">  @Deprecated</span>
+<span class="source-line-no">6226</span><span id="line-6226">  private void replayFlushInStores(FlushDescriptor flush, PrepareFlushResult prepareFlushResult,</span>
+<span class="source-line-no">6227</span><span id="line-6227">    boolean dropMemstoreSnapshot) throws IOException {</span>
+<span class="source-line-no">6228</span><span id="line-6228">    for (StoreFlushDescriptor storeFlush : flush.getStoreFlushesList()) {</span>
+<span class="source-line-no">6229</span><span id="line-6229">      byte[] family = storeFlush.getFamilyName().toByteArray();</span>
+<span class="source-line-no">6230</span><span id="line-6230">      HStore store = getStore(family);</span>
+<span class="source-line-no">6231</span><span id="line-6231">      if (store == null) {</span>
+<span class="source-line-no">6232</span><span id="line-6232">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6233</span><span id="line-6233">          + "Received a flush commit marker from primary, but the family is not found."</span>
+<span class="source-line-no">6234</span><span id="line-6234">          + "Ignoring StoreFlushDescriptor:" + storeFlush);</span>
+<span class="source-line-no">6235</span><span id="line-6235">        continue;</span>
+<span class="source-line-no">6236</span><span id="line-6236">      }</span>
+<span class="source-line-no">6237</span><span id="line-6237">      List&lt;String&gt; flushFiles = storeFlush.getFlushOutputList();</span>
+<span class="source-line-no">6238</span><span id="line-6238">      StoreFlushContext ctx = null;</span>
+<span class="source-line-no">6239</span><span id="line-6239">      long startTime = EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">6240</span><span id="line-6240">      if (prepareFlushResult == null || prepareFlushResult.storeFlushCtxs == null) {</span>
+<span class="source-line-no">6241</span><span id="line-6241">        ctx = store.createFlushContext(flush.getFlushSequenceNumber(), FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">6242</span><span id="line-6242">      } else {</span>
+<span class="source-line-no">6243</span><span id="line-6243">        ctx = prepareFlushResult.storeFlushCtxs.get(family);</span>
+<span class="source-line-no">6244</span><span id="line-6244">        startTime = prepareFlushResult.startTime;</span>
 <span class="source-line-no">6245</span><span id="line-6245">      }</span>
-<span class="source-line-no">6246</span><span id="line-6246">      return totalFreedSize.getMemStoreSize();</span>
-<span class="source-line-no">6247</span><span id="line-6247">    } finally {</span>
-<span class="source-line-no">6248</span><span id="line-6248">      this.updatesLock.writeLock().unlock();</span>
-<span class="source-line-no">6249</span><span id="line-6249">    }</span>
-<span class="source-line-no">6250</span><span id="line-6250">  }</span>
-<span class="source-line-no">6251</span><span id="line-6251"></span>
-<span class="source-line-no">6252</span><span id="line-6252">  /**</span>
-<span class="source-line-no">6253</span><span id="line-6253">   * Drops the memstore contents after replaying a flush descriptor or region open event replay if</span>
-<span class="source-line-no">6254</span><span id="line-6254">   * the memstore edits have seqNums smaller than the given seq id</span>
-<span class="source-line-no">6255</span><span id="line-6255">   */</span>
-<span class="source-line-no">6256</span><span id="line-6256">  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {</span>
-<span class="source-line-no">6257</span><span id="line-6257">    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();</span>
-<span class="source-line-no">6258</span><span id="line-6258">    this.updatesLock.writeLock().lock();</span>
-<span class="source-line-no">6259</span><span id="line-6259">    try {</span>
+<span class="source-line-no">6246</span><span id="line-6246"></span>
+<span class="source-line-no">6247</span><span id="line-6247">      if (ctx == null) {</span>
+<span class="source-line-no">6248</span><span id="line-6248">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6249</span><span id="line-6249">          + "Unexpected: flush commit marker received from store " + Bytes.toString(family)</span>
+<span class="source-line-no">6250</span><span id="line-6250">          + " but no associated flush context. Ignoring");</span>
+<span class="source-line-no">6251</span><span id="line-6251">        continue;</span>
+<span class="source-line-no">6252</span><span id="line-6252">      }</span>
+<span class="source-line-no">6253</span><span id="line-6253"></span>
+<span class="source-line-no">6254</span><span id="line-6254">      ctx.replayFlush(flushFiles, dropMemstoreSnapshot); // replay the flush</span>
+<span class="source-line-no">6255</span><span id="line-6255"></span>
+<span class="source-line-no">6256</span><span id="line-6256">      // Record latest flush time</span>
+<span class="source-line-no">6257</span><span id="line-6257">      this.lastStoreFlushTimeMap.put(store, startTime);</span>
+<span class="source-line-no">6258</span><span id="line-6258">    }</span>
+<span class="source-line-no">6259</span><span id="line-6259">  }</span>
 <span class="source-line-no">6260</span><span id="line-6260"></span>
-<span class="source-line-no">6261</span><span id="line-6261">      long currentSeqId = mvcc.getReadPoint();</span>
-<span class="source-line-no">6262</span><span id="line-6262">      if (seqId &gt;= currentSeqId) {</span>
-<span class="source-line-no">6263</span><span id="line-6263">        // then we can drop the memstore contents since everything is below this seqId</span>
-<span class="source-line-no">6264</span><span id="line-6264">        LOG.info(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6265</span><span id="line-6265">          + "Dropping memstore contents as well since replayed flush seqId: " + seqId</span>
-<span class="source-line-no">6266</span><span id="line-6266">          + " is greater than current seqId:" + currentSeqId);</span>
-<span class="source-line-no">6267</span><span id="line-6267"></span>
-<span class="source-line-no">6268</span><span id="line-6268">        // Prepare flush (take a snapshot) and then abort (drop the snapshot)</span>
-<span class="source-line-no">6269</span><span id="line-6269">        if (store == null) {</span>
-<span class="source-line-no">6270</span><span id="line-6270">          for (HStore s : stores.values()) {</span>
-<span class="source-line-no">6271</span><span id="line-6271">            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));</span>
-<span class="source-line-no">6272</span><span id="line-6272">          }</span>
-<span class="source-line-no">6273</span><span id="line-6273">        } else {</span>
-<span class="source-line-no">6274</span><span id="line-6274">          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));</span>
-<span class="source-line-no">6275</span><span id="line-6275">        }</span>
-<span class="source-line-no">6276</span><span id="line-6276">      } else {</span>
-<span class="source-line-no">6277</span><span id="line-6277">        LOG.info(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6278</span><span id="line-6278">          + "Not dropping memstore contents since replayed flush seqId: " + seqId</span>
-<span class="source-line-no">6279</span><span id="line-6279">          + " is smaller than current seqId:" + currentSeqId);</span>
-<span class="source-line-no">6280</span><span id="line-6280">      }</span>
-<span class="source-line-no">6281</span><span id="line-6281">    } finally {</span>
-<span class="source-line-no">6282</span><span id="line-6282">      this.updatesLock.writeLock().unlock();</span>
-<span class="source-line-no">6283</span><span id="line-6283">    }</span>
-<span class="source-line-no">6284</span><span id="line-6284">    return totalFreedSize.getMemStoreSize();</span>
-<span class="source-line-no">6285</span><span id="line-6285">  }</span>
-<span class="source-line-no">6286</span><span id="line-6286"></span>
-<span class="source-line-no">6287</span><span id="line-6287">  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)</span>
-<span class="source-line-no">6288</span><span id="line-6288">    throws IOException {</span>
-<span class="source-line-no">6289</span><span id="line-6289">    MemStoreSize flushableSize = s.getFlushableSize();</span>
-<span class="source-line-no">6290</span><span id="line-6290">    this.decrMemStoreSize(flushableSize);</span>
-<span class="source-line-no">6291</span><span id="line-6291">    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);</span>
-<span class="source-line-no">6292</span><span id="line-6292">    ctx.prepare();</span>
-<span class="source-line-no">6293</span><span id="line-6293">    ctx.abort();</span>
-<span class="source-line-no">6294</span><span id="line-6294">    return flushableSize;</span>
-<span class="source-line-no">6295</span><span id="line-6295">  }</span>
-<span class="source-line-no">6296</span><span id="line-6296"></span>
-<span class="source-line-no">6297</span><span id="line-6297">  private void replayWALFlushAbortMarker(FlushDescriptor flush) {</span>
-<span class="source-line-no">6298</span><span id="line-6298">    // nothing to do for now. A flush abort will cause a RS abort which means that the region</span>
-<span class="source-line-no">6299</span><span id="line-6299">    // will be opened somewhere else later. We will see the region open event soon, and replaying</span>
-<span class="source-line-no">6300</span><span id="line-6300">    // that will drop the snapshot</span>
-<span class="source-line-no">6301</span><span id="line-6301">  }</span>
-<span class="source-line-no">6302</span><span id="line-6302"></span>
-<span class="source-line-no">6303</span><span id="line-6303">  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {</span>
-<span class="source-line-no">6304</span><span id="line-6304">    synchronized (writestate) {</span>
-<span class="source-line-no">6305</span><span id="line-6305">      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {</span>
-<span class="source-line-no">6306</span><span id="line-6306">        LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying flush event :"</span>
-<span class="source-line-no">6307</span><span id="line-6307">          + TextFormat.shortDebugString(flush) + " because its sequence id " + replaySeqId</span>
-<span class="source-line-no">6308</span><span id="line-6308">          + " is smaller than this regions " + "lastReplayedOpenRegionSeqId of "</span>
-<span class="source-line-no">6309</span><span id="line-6309">          + lastReplayedOpenRegionSeqId);</span>
-<span class="source-line-no">6310</span><span id="line-6310">        return;</span>
-<span class="source-line-no">6311</span><span id="line-6311">      }</span>
-<span class="source-line-no">6312</span><span id="line-6312"></span>
-<span class="source-line-no">6313</span><span id="line-6313">      // If we were waiting for observing a flush or region opening event for not showing partial</span>
-<span class="source-line-no">6314</span><span id="line-6314">      // data after a secondary region crash, we can allow reads now. This event means that the</span>
-<span class="source-line-no">6315</span><span id="line-6315">      // primary was not able to flush because memstore is empty when we requested flush. By the</span>
-<span class="source-line-no">6316</span><span id="line-6316">      // time we observe this, we are guaranteed to have up to date seqId with our previous</span>
-<span class="source-line-no">6317</span><span id="line-6317">      // assignment.</span>
-<span class="source-line-no">6318</span><span id="line-6318">      this.setReadsEnabled(true);</span>
-<span class="source-line-no">6319</span><span id="line-6319">    }</span>
-<span class="source-line-no">6320</span><span id="line-6320">  }</span>
-<span class="source-line-no">6321</span><span id="line-6321"></span>
-<span class="source-line-no">6322</span><span id="line-6322">  PrepareFlushResult getPrepareFlushResult() {</span>
-<span class="source-line-no">6323</span><span id="line-6323">    return prepareFlushResult;</span>
-<span class="source-line-no">6324</span><span id="line-6324">  }</span>
-<span class="source-line-no">6325</span><span id="line-6325"></span>
-<span class="source-line-no">6326</span><span id="line-6326">  /**</span>
-<span class="source-line-no">6327</span><span id="line-6327">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
-<span class="source-line-no">6328</span><span id="line-6328">   *             replica implementation.</span>
-<span class="source-line-no">6329</span><span id="line-6329">   */</span>
-<span class="source-line-no">6330</span><span id="line-6330">  @Deprecated</span>
-<span class="source-line-no">6331</span><span id="line-6331">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",</span>
-<span class="source-line-no">6332</span><span id="line-6332">      justification = "Intentional; cleared the memstore")</span>
-<span class="source-line-no">6333</span><span id="line-6333">  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {</span>
-<span class="source-line-no">6334</span><span id="line-6334">    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),</span>
-<span class="source-line-no">6335</span><span id="line-6335">      "RegionEvent marker from WAL ", regionEvent);</span>
-<span class="source-line-no">6336</span><span id="line-6336"></span>
-<span class="source-line-no">6337</span><span id="line-6337">    startRegionOperation(Operation.REPLAY_EVENT);</span>
-<span class="source-line-no">6338</span><span id="line-6338">    try {</span>
-<span class="source-line-no">6339</span><span id="line-6339">      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
-<span class="source-line-no">6340</span><span id="line-6340">        return; // if primary nothing to do</span>
-<span class="source-line-no">6341</span><span id="line-6341">      }</span>
-<span class="source-line-no">6342</span><span id="line-6342"></span>
-<span class="source-line-no">6343</span><span id="line-6343">      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {</span>
-<span class="source-line-no">6344</span><span id="line-6344">        // nothing to do on REGION_CLOSE for now.</span>
-<span class="source-line-no">6345</span><span id="line-6345">        return;</span>
-<span class="source-line-no">6346</span><span id="line-6346">      }</span>
-<span class="source-line-no">6347</span><span id="line-6347">      if (regionEvent.getEventType() != EventType.REGION_OPEN) {</span>
-<span class="source-line-no">6348</span><span id="line-6348">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6349</span><span id="line-6349">          + "Unknown region event received, ignoring :" + TextFormat.shortDebugString(regionEvent));</span>
-<span class="source-line-no">6350</span><span id="line-6350">        return;</span>
-<span class="source-line-no">6351</span><span id="line-6351">      }</span>
-<span class="source-line-no">6352</span><span id="line-6352"></span>
-<span class="source-line-no">6353</span><span id="line-6353">      if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">6354</span><span id="line-6354">        LOG.debug(getRegionInfo().getEncodedName() + " : " + "Replaying region open event marker "</span>
-<span class="source-line-no">6355</span><span id="line-6355">          + TextFormat.shortDebugString(regionEvent));</span>
-<span class="source-line-no">6356</span><span id="line-6356">      }</span>
-<span class="source-line-no">6357</span><span id="line-6357"></span>
-<span class="source-line-no">6358</span><span id="line-6358">      // we will use writestate as a coarse-grain lock for all the replay events</span>
-<span class="source-line-no">6359</span><span id="line-6359">      synchronized (writestate) {</span>
-<span class="source-line-no">6360</span><span id="line-6360">        // Replication can deliver events out of order when primary region moves or the region</span>
-<span class="source-line-no">6361</span><span id="line-6361">        // server crashes, since there is no coordination between replication of different wal files</span>
-<span class="source-line-no">6362</span><span id="line-6362">        // belonging to different region servers. We have to safe guard against this case by using</span>
-<span class="source-line-no">6363</span><span id="line-6363">        // region open event's seqid. Since this is the first event that the region puts (after</span>
-<span class="source-line-no">6364</span><span id="line-6364">        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit</span>
-<span class="source-line-no">6365</span><span id="line-6365">        // smaller than this seqId</span>
-<span class="source-line-no">6366</span><span id="line-6366">        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {</span>
-<span class="source-line-no">6367</span><span id="line-6367">          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();</span>
-<span class="source-line-no">6368</span><span id="line-6368">        } else {</span>
-<span class="source-line-no">6369</span><span id="line-6369">          LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying region event :"</span>
-<span class="source-line-no">6370</span><span id="line-6370">            + TextFormat.shortDebugString(regionEvent)</span>
-<span class="source-line-no">6371</span><span id="line-6371">            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "</span>
-<span class="source-line-no">6372</span><span id="line-6372">            + " of " + lastReplayedOpenRegionSeqId);</span>
-<span class="source-line-no">6373</span><span id="line-6373">          return;</span>
-<span class="source-line-no">6374</span><span id="line-6374">        }</span>
+<span class="source-line-no">6261</span><span id="line-6261">  private long loadRecoveredHFilesIfAny(Collection&lt;HStore&gt; stores) throws IOException {</span>
+<span class="source-line-no">6262</span><span id="line-6262">    Path regionDir = fs.getRegionDir();</span>
+<span class="source-line-no">6263</span><span id="line-6263">    long maxSeqId = -1;</span>
+<span class="source-line-no">6264</span><span id="line-6264">    for (HStore store : stores) {</span>
+<span class="source-line-no">6265</span><span id="line-6265">      String familyName = store.getColumnFamilyName();</span>
+<span class="source-line-no">6266</span><span id="line-6266">      FileStatus[] files =</span>
+<span class="source-line-no">6267</span><span id="line-6267">        WALSplitUtil.getRecoveredHFiles(fs.getFileSystem(), regionDir, familyName);</span>
+<span class="source-line-no">6268</span><span id="line-6268">      if (files != null &amp;&amp; files.length != 0) {</span>
+<span class="source-line-no">6269</span><span id="line-6269">        for (FileStatus file : files) {</span>
+<span class="source-line-no">6270</span><span id="line-6270">          Path filePath = file.getPath();</span>
+<span class="source-line-no">6271</span><span id="line-6271">          // If file length is zero then delete it</span>
+<span class="source-line-no">6272</span><span id="line-6272">          if (isZeroLengthThenDelete(fs.getFileSystem(), file, filePath)) {</span>
+<span class="source-line-no">6273</span><span id="line-6273">            continue;</span>
+<span class="source-line-no">6274</span><span id="line-6274">          }</span>
+<span class="source-line-no">6275</span><span id="line-6275">          try {</span>
+<span class="source-line-no">6276</span><span id="line-6276">            HStoreFile storefile = store.tryCommitRecoveredHFile(file.getPath());</span>
+<span class="source-line-no">6277</span><span id="line-6277">            maxSeqId = Math.max(maxSeqId, storefile.getReader().getSequenceID());</span>
+<span class="source-line-no">6278</span><span id="line-6278">          } catch (IOException e) {</span>
+<span class="source-line-no">6279</span><span id="line-6279">            handleException(fs.getFileSystem(), filePath, e);</span>
+<span class="source-line-no">6280</span><span id="line-6280">            continue;</span>
+<span class="source-line-no">6281</span><span id="line-6281">          }</span>
+<span class="source-line-no">6282</span><span id="line-6282">        }</span>
+<span class="source-line-no">6283</span><span id="line-6283">        if (this.rsServices != null &amp;&amp; store.needsCompaction()) {</span>
+<span class="source-line-no">6284</span><span id="line-6284">          this.rsServices.getCompactionRequestor().requestCompaction(this, store,</span>
+<span class="source-line-no">6285</span><span id="line-6285">            "load recovered hfiles request compaction", Store.PRIORITY_USER + 1,</span>
+<span class="source-line-no">6286</span><span id="line-6286">            CompactionLifeCycleTracker.DUMMY, null);</span>
+<span class="source-line-no">6287</span><span id="line-6287">        }</span>
+<span class="source-line-no">6288</span><span id="line-6288">      }</span>
+<span class="source-line-no">6289</span><span id="line-6289">    }</span>
+<span class="source-line-no">6290</span><span id="line-6290">    return maxSeqId;</span>
+<span class="source-line-no">6291</span><span id="line-6291">  }</span>
+<span class="source-line-no">6292</span><span id="line-6292"></span>
+<span class="source-line-no">6293</span><span id="line-6293">  /**</span>
+<span class="source-line-no">6294</span><span id="line-6294">   * Be careful, this method will drop all data in the memstore of this region. Currently, this</span>
+<span class="source-line-no">6295</span><span id="line-6295">   * method is used to drop memstore to prevent memory leak when replaying recovered.edits while</span>
+<span class="source-line-no">6296</span><span id="line-6296">   * opening region.</span>
+<span class="source-line-no">6297</span><span id="line-6297">   */</span>
+<span class="source-line-no">6298</span><span id="line-6298">  private MemStoreSize dropMemStoreContents() throws IOException {</span>
+<span class="source-line-no">6299</span><span id="line-6299">    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();</span>
+<span class="source-line-no">6300</span><span id="line-6300">    this.updatesLock.writeLock().lock();</span>
+<span class="source-line-no">6301</span><span id="line-6301">    try {</span>
+<span class="source-line-no">6302</span><span id="line-6302">      for (HStore s : stores.values()) {</span>
+<span class="source-line-no">6303</span><span id="line-6303">        MemStoreSize memStoreSize = doDropStoreMemStoreContentsForSeqId(s, HConstants.NO_SEQNUM);</span>
+<span class="source-line-no">6304</span><span id="line-6304">        LOG.info("Drop memstore for Store " + s.getColumnFamilyName() + " in region "</span>
+<span class="source-line-no">6305</span><span id="line-6305">          + this.getRegionInfo().getRegionNameAsString() + " , dropped memstoresize: ["</span>
+<span class="source-line-no">6306</span><span id="line-6306">          + memStoreSize + " }");</span>
+<span class="source-line-no">6307</span><span id="line-6307">        totalFreedSize.incMemStoreSize(memStoreSize);</span>
+<span class="source-line-no">6308</span><span id="line-6308">      }</span>
+<span class="source-line-no">6309</span><span id="line-6309">      return totalFreedSize.getMemStoreSize();</span>
+<span class="source-line-no">6310</span><span id="line-6310">    } finally {</span>
+<span class="source-line-no">6311</span><span id="line-6311">      this.updatesLock.writeLock().unlock();</span>
+<span class="source-line-no">6312</span><span id="line-6312">    }</span>
+<span class="source-line-no">6313</span><span id="line-6313">  }</span>
+<span class="source-line-no">6314</span><span id="line-6314"></span>
+<span class="source-line-no">6315</span><span id="line-6315">  /**</span>
+<span class="source-line-no">6316</span><span id="line-6316">   * Drops the memstore contents after replaying a flush descriptor or region open event replay if</span>
+<span class="source-line-no">6317</span><span id="line-6317">   * the memstore edits have seqNums smaller than the given seq id</span>
+<span class="source-line-no">6318</span><span id="line-6318">   */</span>
+<span class="source-line-no">6319</span><span id="line-6319">  private MemStoreSize dropMemStoreContentsForSeqId(long seqId, HStore store) throws IOException {</span>
+<span class="source-line-no">6320</span><span id="line-6320">    MemStoreSizing totalFreedSize = new NonThreadSafeMemStoreSizing();</span>
+<span class="source-line-no">6321</span><span id="line-6321">    this.updatesLock.writeLock().lock();</span>
+<span class="source-line-no">6322</span><span id="line-6322">    try {</span>
+<span class="source-line-no">6323</span><span id="line-6323"></span>
+<span class="source-line-no">6324</span><span id="line-6324">      long currentSeqId = mvcc.getReadPoint();</span>
+<span class="source-line-no">6325</span><span id="line-6325">      if (seqId &gt;= currentSeqId) {</span>
+<span class="source-line-no">6326</span><span id="line-6326">        // then we can drop the memstore contents since everything is below this seqId</span>
+<span class="source-line-no">6327</span><span id="line-6327">        LOG.info(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6328</span><span id="line-6328">          + "Dropping memstore contents as well since replayed flush seqId: " + seqId</span>
+<span class="source-line-no">6329</span><span id="line-6329">          + " is greater than current seqId:" + currentSeqId);</span>
+<span class="source-line-no">6330</span><span id="line-6330"></span>
+<span class="source-line-no">6331</span><span id="line-6331">        // Prepare flush (take a snapshot) and then abort (drop the snapshot)</span>
+<span class="source-line-no">6332</span><span id="line-6332">        if (store == null) {</span>
+<span class="source-line-no">6333</span><span id="line-6333">          for (HStore s : stores.values()) {</span>
+<span class="source-line-no">6334</span><span id="line-6334">            totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(s, currentSeqId));</span>
+<span class="source-line-no">6335</span><span id="line-6335">          }</span>
+<span class="source-line-no">6336</span><span id="line-6336">        } else {</span>
+<span class="source-line-no">6337</span><span id="line-6337">          totalFreedSize.incMemStoreSize(doDropStoreMemStoreContentsForSeqId(store, currentSeqId));</span>
+<span class="source-line-no">6338</span><span id="line-6338">        }</span>
+<span class="source-line-no">6339</span><span id="line-6339">      } else {</span>
+<span class="source-line-no">6340</span><span id="line-6340">        LOG.info(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6341</span><span id="line-6341">          + "Not dropping memstore contents since replayed flush seqId: " + seqId</span>
+<span class="source-line-no">6342</span><span id="line-6342">          + " is smaller than current seqId:" + currentSeqId);</span>
+<span class="source-line-no">6343</span><span id="line-6343">      }</span>
+<span class="source-line-no">6344</span><span id="line-6344">    } finally {</span>
+<span class="source-line-no">6345</span><span id="line-6345">      this.updatesLock.writeLock().unlock();</span>
+<span class="source-line-no">6346</span><span id="line-6346">    }</span>
+<span class="source-line-no">6347</span><span id="line-6347">    return totalFreedSize.getMemStoreSize();</span>
+<span class="source-line-no">6348</span><span id="line-6348">  }</span>
+<span class="source-line-no">6349</span><span id="line-6349"></span>
+<span class="source-line-no">6350</span><span id="line-6350">  private MemStoreSize doDropStoreMemStoreContentsForSeqId(HStore s, long currentSeqId)</span>
+<span class="source-line-no">6351</span><span id="line-6351">    throws IOException {</span>
+<span class="source-line-no">6352</span><span id="line-6352">    MemStoreSize flushableSize = s.getFlushableSize();</span>
+<span class="source-line-no">6353</span><span id="line-6353">    this.decrMemStoreSize(flushableSize);</span>
+<span class="source-line-no">6354</span><span id="line-6354">    StoreFlushContext ctx = s.createFlushContext(currentSeqId, FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">6355</span><span id="line-6355">    ctx.prepare();</span>
+<span class="source-line-no">6356</span><span id="line-6356">    ctx.abort();</span>
+<span class="source-line-no">6357</span><span id="line-6357">    return flushableSize;</span>
+<span class="source-line-no">6358</span><span id="line-6358">  }</span>
+<span class="source-line-no">6359</span><span id="line-6359"></span>
+<span class="source-line-no">6360</span><span id="line-6360">  private void replayWALFlushAbortMarker(FlushDescriptor flush) {</span>
+<span class="source-line-no">6361</span><span id="line-6361">    // nothing to do for now. A flush abort will cause a RS abort which means that the region</span>
+<span class="source-line-no">6362</span><span id="line-6362">    // will be opened somewhere else later. We will see the region open event soon, and replaying</span>
+<span class="source-line-no">6363</span><span id="line-6363">    // that will drop the snapshot</span>
+<span class="source-line-no">6364</span><span id="line-6364">  }</span>
+<span class="source-line-no">6365</span><span id="line-6365"></span>
+<span class="source-line-no">6366</span><span id="line-6366">  private void replayWALFlushCannotFlushMarker(FlushDescriptor flush, long replaySeqId) {</span>
+<span class="source-line-no">6367</span><span id="line-6367">    synchronized (writestate) {</span>
+<span class="source-line-no">6368</span><span id="line-6368">      if (this.lastReplayedOpenRegionSeqId &gt; replaySeqId) {</span>
+<span class="source-line-no">6369</span><span id="line-6369">        LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying flush event :"</span>
+<span class="source-line-no">6370</span><span id="line-6370">          + TextFormat.shortDebugString(flush) + " because its sequence id " + replaySeqId</span>
+<span class="source-line-no">6371</span><span id="line-6371">          + " is smaller than this regions " + "lastReplayedOpenRegionSeqId of "</span>
+<span class="source-line-no">6372</span><span id="line-6372">          + lastReplayedOpenRegionSeqId);</span>
+<span class="source-line-no">6373</span><span id="line-6373">        return;</span>
+<span class="source-line-no">6374</span><span id="line-6374">      }</span>
 <span class="source-line-no">6375</span><span id="line-6375"></span>
-<span class="source-line-no">6376</span><span id="line-6376">        // region open lists all the files that the region has at the time of the opening. Just pick</span>
-<span class="source-line-no">6377</span><span id="line-6377">        // all the files and drop prepared flushes and empty memstores</span>
-<span class="source-line-no">6378</span><span id="line-6378">        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {</span>
-<span class="source-line-no">6379</span><span id="line-6379">          // stores of primary may be different now</span>
-<span class="source-line-no">6380</span><span id="line-6380">          byte[] family = storeDescriptor.getFamilyName().toByteArray();</span>
-<span class="source-line-no">6381</span><span id="line-6381">          HStore store = getStore(family);</span>
-<span class="source-line-no">6382</span><span id="line-6382">          if (store == null) {</span>
-<span class="source-line-no">6383</span><span id="line-6383">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6384</span><span id="line-6384">              + "Received a region open marker from primary, but the family is not found. "</span>
-<span class="source-line-no">6385</span><span id="line-6385">              + "Ignoring. StoreDescriptor:" + storeDescriptor);</span>
-<span class="source-line-no">6386</span><span id="line-6386">            continue;</span>
-<span class="source-line-no">6387</span><span id="line-6387">          }</span>
+<span class="source-line-no">6376</span><span id="line-6376">      // If we were waiting for observing a flush or region opening event for not showing partial</span>
+<span class="source-line-no">6377</span><span id="line-6377">      // data after a secondary region crash, we can allow reads now. This event means that the</span>
+<span class="source-line-no">6378</span><span id="line-6378">      // primary was not able to flush because memstore is empty when we requested flush. By the</span>
+<span class="source-line-no">6379</span><span id="line-6379">      // time we observe this, we are guaranteed to have up to date seqId with our previous</span>
+<span class="source-line-no">6380</span><span id="line-6380">      // assignment.</span>
+<span class="source-line-no">6381</span><span id="line-6381">      this.setReadsEnabled(true);</span>
+<span class="source-line-no">6382</span><span id="line-6382">    }</span>
+<span class="source-line-no">6383</span><span id="line-6383">  }</span>
+<span class="source-line-no">6384</span><span id="line-6384"></span>
+<span class="source-line-no">6385</span><span id="line-6385">  PrepareFlushResult getPrepareFlushResult() {</span>
+<span class="source-line-no">6386</span><span id="line-6386">    return prepareFlushResult;</span>
+<span class="source-line-no">6387</span><span id="line-6387">  }</span>
 <span class="source-line-no">6388</span><span id="line-6388"></span>
-<span class="source-line-no">6389</span><span id="line-6389">          long storeSeqId = store.getMaxSequenceId().orElse(0L);</span>
-<span class="source-line-no">6390</span><span id="line-6390">          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();</span>
-<span class="source-line-no">6391</span><span id="line-6391">          try {</span>
-<span class="source-line-no">6392</span><span id="line-6392">            store.refreshStoreFiles(storeFiles); // replace the files with the new ones</span>
-<span class="source-line-no">6393</span><span id="line-6393">          } catch (FileNotFoundException ex) {</span>
-<span class="source-line-no">6394</span><span id="line-6394">            LOG.warn(getRegionInfo().getEncodedName() + " : " + "At least one of the store files: "</span>
-<span class="source-line-no">6395</span><span id="line-6395">              + storeFiles + " doesn't exist any more. Skip loading the file(s)", ex);</span>
-<span class="source-line-no">6396</span><span id="line-6396">            continue;</span>
-<span class="source-line-no">6397</span><span id="line-6397">          }</span>
-<span class="source-line-no">6398</span><span id="line-6398">          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {</span>
-<span class="source-line-no">6399</span><span id="line-6399">            // Record latest flush time if we picked up new files</span>
-<span class="source-line-no">6400</span><span id="line-6400">            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());</span>
-<span class="source-line-no">6401</span><span id="line-6401">          }</span>
-<span class="source-line-no">6402</span><span id="line-6402"></span>
-<span class="source-line-no">6403</span><span id="line-6403">          if (writestate.flushing) {</span>
-<span class="source-line-no">6404</span><span id="line-6404">            // only drop memstore snapshots if they are smaller than last flush for the store</span>
-<span class="source-line-no">6405</span><span id="line-6405">            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {</span>
-<span class="source-line-no">6406</span><span id="line-6406">              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null</span>
-<span class="source-line-no">6407</span><span id="line-6407">                ? null</span>
-<span class="source-line-no">6408</span><span id="line-6408">                : this.prepareFlushResult.storeFlushCtxs.get(family);</span>
-<span class="source-line-no">6409</span><span id="line-6409">              if (ctx != null) {</span>
-<span class="source-line-no">6410</span><span id="line-6410">                MemStoreSize mss = store.getFlushableSize();</span>
-<span class="source-line-no">6411</span><span id="line-6411">                ctx.abort();</span>
-<span class="source-line-no">6412</span><span id="line-6412">                this.decrMemStoreSize(mss);</span>
-<span class="source-line-no">6413</span><span id="line-6413">                this.prepareFlushResult.storeFlushCtxs.remove(family);</span>
-<span class="source-line-no">6414</span><span id="line-6414">              }</span>
-<span class="source-line-no">6415</span><span id="line-6415">            }</span>
-<span class="source-line-no">6416</span><span id="line-6416">          }</span>
-<span class="source-line-no">6417</span><span id="line-6417"></span>
-<span class="source-line-no">6418</span><span id="line-6418">          // Drop the memstore contents if they are now smaller than the latest seen flushed file</span>
-<span class="source-line-no">6419</span><span id="line-6419">          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);</span>
-<span class="source-line-no">6420</span><span id="line-6420">          if (storeSeqId &gt; this.maxFlushedSeqId) {</span>
-<span class="source-line-no">6421</span><span id="line-6421">            this.maxFlushedSeqId = storeSeqId;</span>
-<span class="source-line-no">6422</span><span id="line-6422">          }</span>
-<span class="source-line-no">6423</span><span id="line-6423">        }</span>
-<span class="source-line-no">6424</span><span id="line-6424"></span>
-<span class="source-line-no">6425</span><span id="line-6425">        // if all stores ended up dropping their snapshots, we can safely drop the</span>
-<span class="source-line-no">6426</span><span id="line-6426">        // prepareFlushResult</span>
-<span class="source-line-no">6427</span><span id="line-6427">        dropPrepareFlushIfPossible();</span>
-<span class="source-line-no">6428</span><span id="line-6428"></span>
-<span class="source-line-no">6429</span><span id="line-6429">        // advance the mvcc read point so that the new flushed file is visible.</span>
-<span class="source-line-no">6430</span><span id="line-6430">        mvcc.await();</span>
-<span class="source-line-no">6431</span><span id="line-6431"></span>
-<span class="source-line-no">6432</span><span id="line-6432">        // If we were waiting for observing a flush or region opening event for not showing partial</span>
-<span class="source-line-no">6433</span><span id="line-6433">        // data after a secondary region crash, we can allow reads now.</span>
-<span class="source-line-no">6434</span><span id="line-6434">        this.setReadsEnabled(true);</span>
-<span class="source-line-no">6435</span><span id="line-6435"></span>
-<span class="source-line-no">6436</span><span id="line-6436">        // C. Finally notify anyone waiting on memstore to clear:</span>
-<span class="source-line-no">6437</span><span id="line-6437">        // e.g. checkResources().</span>
-<span class="source-line-no">6438</span><span id="line-6438">        synchronized (this) {</span>
-<span class="source-line-no">6439</span><span id="line-6439">          notifyAll(); // FindBugs NN_NAKED_NOTIFY</span>
-<span class="source-line-no">6440</span><span id="line-6440">        }</span>
-<span class="source-line-no">6441</span><span id="line-6441">      }</span>
-<span class="source-line-no">6442</span><span id="line-6442">      logRegionFiles();</span>
-<span class="source-line-no">6443</span><span id="line-6443">    } finally {</span>
-<span class="source-line-no">6444</span><span id="line-6444">      closeRegionOperation(Operation.REPLAY_EVENT);</span>
-<span class="source-line-no">6445</span><span id="line-6445">    }</span>
-<span class="source-line-no">6446</span><span id="line-6446">  }</span>
-<span class="source-line-no">6447</span><span id="line-6447"></span>
-<span class="source-line-no">6448</span><span id="line-6448">  /**</span>
-<span class="source-line-no">6449</span><span id="line-6449">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
-<span class="source-line-no">6450</span><span id="line-6450">   *             replica implementation.</span>
-<span class="source-line-no">6451</span><span id="line-6451">   */</span>
-<span class="source-line-no">6452</span><span id="line-6452">  @Deprecated</span>
-<span class="source-line-no">6453</span><span id="line-6453">  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {</span>
-<span class="source-line-no">6454</span><span id="line-6454">    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),</span>
-<span class="source-line-no">6455</span><span id="line-6455">      "BulkLoad marker from WAL ", bulkLoadEvent);</span>
-<span class="source-line-no">6456</span><span id="line-6456"></span>
-<span class="source-line-no">6457</span><span id="line-6457">    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
-<span class="source-line-no">6458</span><span id="line-6458">      return; // if primary nothing to do</span>
-<span class="source-line-no">6459</span><span id="line-6459">    }</span>
-<span class="source-line-no">6460</span><span id="line-6460"></span>
-<span class="source-line-no">6461</span><span id="line-6461">    if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">6462</span><span id="line-6462">      LOG.debug(getRegionInfo().getEncodedName() + " : " + "Replaying bulkload event marker "</span>
-<span class="source-line-no">6463</span><span id="line-6463">        + TextFormat.shortDebugString(bulkLoadEvent));</span>
-<span class="source-line-no">6464</span><span id="line-6464">    }</span>
-<span class="source-line-no">6465</span><span id="line-6465">    // check if multiple families involved</span>
-<span class="source-line-no">6466</span><span id="line-6466">    boolean multipleFamilies = false;</span>
-<span class="source-line-no">6467</span><span id="line-6467">    byte[] family = null;</span>
-<span class="source-line-no">6468</span><span id="line-6468">    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {</span>
-<span class="source-line-no">6469</span><span id="line-6469">      byte[] fam = storeDescriptor.getFamilyName().toByteArray();</span>
-<span class="source-line-no">6470</span><span id="line-6470">      if (family == null) {</span>
-<span class="source-line-no">6471</span><span id="line-6471">        family = fam;</span>
-<span class="source-line-no">6472</span><span id="line-6472">      } else if (!Bytes.equals(family, fam)) {</span>
-<span class="source-line-no">6473</span><span id="line-6473">        multipleFamilies = true;</span>
-<span class="source-line-no">6474</span><span id="line-6474">        break;</span>
-<span class="source-line-no">6475</span><span id="line-6475">      }</span>
-<span class="source-line-no">6476</span><span id="line-6476">    }</span>
-<span class="source-line-no">6477</span><span id="line-6477"></span>
-<span class="source-line-no">6478</span><span id="line-6478">    startBulkRegionOperation(multipleFamilies);</span>
-<span class="source-line-no">6479</span><span id="line-6479">    try {</span>
-<span class="source-line-no">6480</span><span id="line-6480">      // we will use writestate as a coarse-grain lock for all the replay events</span>
-<span class="source-line-no">6481</span><span id="line-6481">      synchronized (writestate) {</span>
-<span class="source-line-no">6482</span><span id="line-6482">        // Replication can deliver events out of order when primary region moves or the region</span>
-<span class="source-line-no">6483</span><span id="line-6483">        // server crashes, since there is no coordination between replication of different wal files</span>
-<span class="source-line-no">6484</span><span id="line-6484">        // belonging to different region servers. We have to safe guard against this case by using</span>
-<span class="source-line-no">6485</span><span id="line-6485">        // region open event's seqid. Since this is the first event that the region puts (after</span>
-<span class="source-line-no">6486</span><span id="line-6486">        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit</span>
-<span class="source-line-no">6487</span><span id="line-6487">        // smaller than this seqId</span>
-<span class="source-line-no">6488</span><span id="line-6488">        if (</span>
-<span class="source-line-no">6489</span><span id="line-6489">          bulkLoadEvent.getBulkloadSeqNum() &gt;= 0</span>
-<span class="source-line-no">6490</span><span id="line-6490">            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()</span>
-<span class="source-line-no">6491</span><span id="line-6491">        ) {</span>
-<span class="source-line-no">6492</span><span id="line-6492">          LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying bulkload event :"</span>
-<span class="source-line-no">6493</span><span id="line-6493">            + TextFormat.shortDebugString(bulkLoadEvent)</span>
-<span class="source-line-no">6494</span><span id="line-6494">            + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"</span>
-<span class="source-line-no">6495</span><span id="line-6495">            + " =" + lastReplayedOpenRegionSeqId);</span>
-<span class="source-line-no">6496</span><span id="line-6496"></span>
-<span class="source-line-no">6497</span><span id="line-6497">          return;</span>
-<span class="source-line-no">6498</span><span id="line-6498">        }</span>
-<span class="source-line-no">6499</span><span id="line-6499"></span>
-<span class="source-line-no">6500</span><span id="line-6500">        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {</span>
-<span class="source-line-no">6501</span><span id="line-6501">          // stores of primary may be different now</span>
-<span class="source-line-no">6502</span><span id="line-6502">          family = storeDescriptor.getFamilyName().toByteArray();</span>
-<span class="source-line-no">6503</span><span id="line-6503">          HStore store = getStore(family);</span>
-<span class="source-line-no">6504</span><span id="line-6504">          if (store == null) {</span>
-<span class="source-line-no">6505</span><span id="line-6505">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6506</span><span id="line-6506">              + "Received a bulk load marker from primary, but the family is not found. "</span>
-<span class="source-line-no">6507</span><span id="line-6507">              + "Ignoring. StoreDescriptor:" + storeDescriptor);</span>
-<span class="source-line-no">6508</span><span id="line-6508">            continue;</span>
-<span class="source-line-no">6509</span><span id="line-6509">          }</span>
+<span class="source-line-no">6389</span><span id="line-6389">  /**</span>
+<span class="source-line-no">6390</span><span id="line-6390">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
+<span class="source-line-no">6391</span><span id="line-6391">   *             replica implementation.</span>
+<span class="source-line-no">6392</span><span id="line-6392">   */</span>
+<span class="source-line-no">6393</span><span id="line-6393">  @Deprecated</span>
+<span class="source-line-no">6394</span><span id="line-6394">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",</span>
+<span class="source-line-no">6395</span><span id="line-6395">      justification = "Intentional; cleared the memstore")</span>
+<span class="source-line-no">6396</span><span id="line-6396">  void replayWALRegionEventMarker(RegionEventDescriptor regionEvent) throws IOException {</span>
+<span class="source-line-no">6397</span><span id="line-6397">    checkTargetRegion(regionEvent.getEncodedRegionName().toByteArray(),</span>
+<span class="source-line-no">6398</span><span id="line-6398">      "RegionEvent marker from WAL ", regionEvent);</span>
+<span class="source-line-no">6399</span><span id="line-6399"></span>
+<span class="source-line-no">6400</span><span id="line-6400">    startRegionOperation(Operation.REPLAY_EVENT);</span>
+<span class="source-line-no">6401</span><span id="line-6401">    try {</span>
+<span class="source-line-no">6402</span><span id="line-6402">      if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
+<span class="source-line-no">6403</span><span id="line-6403">        return; // if primary nothing to do</span>
+<span class="source-line-no">6404</span><span id="line-6404">      }</span>
+<span class="source-line-no">6405</span><span id="line-6405"></span>
+<span class="source-line-no">6406</span><span id="line-6406">      if (regionEvent.getEventType() == EventType.REGION_CLOSE) {</span>
+<span class="source-line-no">6407</span><span id="line-6407">        // nothing to do on REGION_CLOSE for now.</span>
+<span class="source-line-no">6408</span><span id="line-6408">        return;</span>
+<span class="source-line-no">6409</span><span id="line-6409">      }</span>
+<span class="source-line-no">6410</span><span id="line-6410">      if (regionEvent.getEventType() != EventType.REGION_OPEN) {</span>
+<span class="source-line-no">6411</span><span id="line-6411">        LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6412</span><span id="line-6412">          + "Unknown region event received, ignoring :" + TextFormat.shortDebugString(regionEvent));</span>
+<span class="source-line-no">6413</span><span id="line-6413">        return;</span>
+<span class="source-line-no">6414</span><span id="line-6414">      }</span>
+<span class="source-line-no">6415</span><span id="line-6415"></span>
+<span class="source-line-no">6416</span><span id="line-6416">      if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">6417</span><span id="line-6417">        LOG.debug(getRegionInfo().getEncodedName() + " : " + "Replaying region open event marker "</span>
+<span class="source-line-no">6418</span><span id="line-6418">          + TextFormat.shortDebugString(regionEvent));</span>
+<span class="source-line-no">6419</span><span id="line-6419">      }</span>
+<span class="source-line-no">6420</span><span id="line-6420"></span>
+<span class="source-line-no">6421</span><span id="line-6421">      // we will use writestate as a coarse-grain lock for all the replay events</span>
+<span class="source-line-no">6422</span><span id="line-6422">      synchronized (writestate) {</span>
+<span class="source-line-no">6423</span><span id="line-6423">        // Replication can deliver events out of order when primary region moves or the region</span>
+<span class="source-line-no">6424</span><span id="line-6424">        // server crashes, since there is no coordination between replication of different wal files</span>
+<span class="source-line-no">6425</span><span id="line-6425">        // belonging to different region servers. We have to safe guard against this case by using</span>
+<span class="source-line-no">6426</span><span id="line-6426">        // region open event's seqid. Since this is the first event that the region puts (after</span>
+<span class="source-line-no">6427</span><span id="line-6427">        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit</span>
+<span class="source-line-no">6428</span><span id="line-6428">        // smaller than this seqId</span>
+<span class="source-line-no">6429</span><span id="line-6429">        if (this.lastReplayedOpenRegionSeqId &lt;= regionEvent.getLogSequenceNumber()) {</span>
+<span class="source-line-no">6430</span><span id="line-6430">          this.lastReplayedOpenRegionSeqId = regionEvent.getLogSequenceNumber();</span>
+<span class="source-line-no">6431</span><span id="line-6431">        } else {</span>
+<span class="source-line-no">6432</span><span id="line-6432">          LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying region event :"</span>
+<span class="source-line-no">6433</span><span id="line-6433">            + TextFormat.shortDebugString(regionEvent)</span>
+<span class="source-line-no">6434</span><span id="line-6434">            + " because its sequence id is smaller than this regions lastReplayedOpenRegionSeqId "</span>
+<span class="source-line-no">6435</span><span id="line-6435">            + " of " + lastReplayedOpenRegionSeqId);</span>
+<span class="source-line-no">6436</span><span id="line-6436">          return;</span>
+<span class="source-line-no">6437</span><span id="line-6437">        }</span>
+<span class="source-line-no">6438</span><span id="line-6438"></span>
+<span class="source-line-no">6439</span><span id="line-6439">        // region open lists all the files that the region has at the time of the opening. Just pick</span>
+<span class="source-line-no">6440</span><span id="line-6440">        // all the files and drop prepared flushes and empty memstores</span>
+<span class="source-line-no">6441</span><span id="line-6441">        for (StoreDescriptor storeDescriptor : regionEvent.getStoresList()) {</span>
+<span class="source-line-no">6442</span><span id="line-6442">          // stores of primary may be different now</span>
+<span class="source-line-no">6443</span><span id="line-6443">          byte[] family = storeDescriptor.getFamilyName().toByteArray();</span>
+<span class="source-line-no">6444</span><span id="line-6444">          HStore store = getStore(family);</span>
+<span class="source-line-no">6445</span><span id="line-6445">          if (store == null) {</span>
+<span class="source-line-no">6446</span><span id="line-6446">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6447</span><span id="line-6447">              + "Received a region open marker from primary, but the family is not found. "</span>
+<span class="source-line-no">6448</span><span id="line-6448">              + "Ignoring. StoreDescriptor:" + storeDescriptor);</span>
+<span class="source-line-no">6449</span><span id="line-6449">            continue;</span>
+<span class="source-line-no">6450</span><span id="line-6450">          }</span>
+<span class="source-line-no">6451</span><span id="line-6451"></span>
+<span class="source-line-no">6452</span><span id="line-6452">          long storeSeqId = store.getMaxSequenceId().orElse(0L);</span>
+<span class="source-line-no">6453</span><span id="line-6453">          List&lt;String&gt; storeFiles = storeDescriptor.getStoreFileList();</span>
+<span class="source-line-no">6454</span><span id="line-6454">          try {</span>
+<span class="source-line-no">6455</span><span id="line-6455">            store.refreshStoreFiles(storeFiles); // replace the files with the new ones</span>
+<span class="source-line-no">6456</span><span id="line-6456">          } catch (FileNotFoundException ex) {</span>
+<span class="source-line-no">6457</span><span id="line-6457">            LOG.warn(getRegionInfo().getEncodedName() + " : " + "At least one of the store files: "</span>
+<span class="source-line-no">6458</span><span id="line-6458">              + storeFiles + " doesn't exist any more. Skip loading the file(s)", ex);</span>
+<span class="source-line-no">6459</span><span id="line-6459">            continue;</span>
+<span class="source-line-no">6460</span><span id="line-6460">          }</span>
+<span class="source-line-no">6461</span><span id="line-6461">          if (store.getMaxSequenceId().orElse(0L) != storeSeqId) {</span>
+<span class="source-line-no">6462</span><span id="line-6462">            // Record latest flush time if we picked up new files</span>
+<span class="source-line-no">6463</span><span id="line-6463">            lastStoreFlushTimeMap.put(store, EnvironmentEdgeManager.currentTime());</span>
+<span class="source-line-no">6464</span><span id="line-6464">          }</span>
+<span class="source-line-no">6465</span><span id="line-6465"></span>
+<span class="source-line-no">6466</span><span id="line-6466">          if (writestate.flushing) {</span>
+<span class="source-line-no">6467</span><span id="line-6467">            // only drop memstore snapshots if they are smaller than last flush for the store</span>
+<span class="source-line-no">6468</span><span id="line-6468">            if (this.prepareFlushResult.flushOpSeqId &lt;= regionEvent.getLogSequenceNumber()) {</span>
+<span class="source-line-no">6469</span><span id="line-6469">              StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null</span>
+<span class="source-line-no">6470</span><span id="line-6470">                ? null</span>
+<span class="source-line-no">6471</span><span id="line-6471">                : this.prepareFlushResult.storeFlushCtxs.get(family);</span>
+<span class="source-line-no">6472</span><span id="line-6472">              if (ctx != null) {</span>
+<span class="source-line-no">6473</span><span id="line-6473">                MemStoreSize mss = store.getFlushableSize();</span>
+<span class="source-line-no">6474</span><span id="line-6474">                ctx.abort();</span>
+<span class="source-line-no">6475</span><span id="line-6475">                this.decrMemStoreSize(mss);</span>
+<span class="source-line-no">6476</span><span id="line-6476">                this.prepareFlushResult.storeFlushCtxs.remove(family);</span>
+<span class="source-line-no">6477</span><span id="line-6477">              }</span>
+<span class="source-line-no">6478</span><span id="line-6478">            }</span>
+<span class="source-line-no">6479</span><span id="line-6479">          }</span>
+<span class="source-line-no">6480</span><span id="line-6480"></span>
+<span class="source-line-no">6481</span><span id="line-6481">          // Drop the memstore contents if they are now smaller than the latest seen flushed file</span>
+<span class="source-line-no">6482</span><span id="line-6482">          dropMemStoreContentsForSeqId(regionEvent.getLogSequenceNumber(), store);</span>
+<span class="source-line-no">6483</span><span id="line-6483">          if (storeSeqId &gt; this.maxFlushedSeqId) {</span>
+<span class="source-line-no">6484</span><span id="line-6484">            this.maxFlushedSeqId = storeSeqId;</span>
+<span class="source-line-no">6485</span><span id="line-6485">          }</span>
+<span class="source-line-no">6486</span><span id="line-6486">        }</span>
+<span class="source-line-no">6487</span><span id="line-6487"></span>
+<span class="source-line-no">6488</span><span id="line-6488">        // if all stores ended up dropping their snapshots, we can safely drop the</span>
+<span class="source-line-no">6489</span><span id="line-6489">        // prepareFlushResult</span>
+<span class="source-line-no">6490</span><span id="line-6490">        dropPrepareFlushIfPossible();</span>
+<span class="source-line-no">6491</span><span id="line-6491"></span>
+<span class="source-line-no">6492</span><span id="line-6492">        // advance the mvcc read point so that the new flushed file is visible.</span>
+<span class="source-line-no">6493</span><span id="line-6493">        mvcc.await();</span>
+<span class="source-line-no">6494</span><span id="line-6494"></span>
+<span class="source-line-no">6495</span><span id="line-6495">        // If we were waiting for observing a flush or region opening event for not showing partial</span>
+<span class="source-line-no">6496</span><span id="line-6496">        // data after a secondary region crash, we can allow reads now.</span>
+<span class="source-line-no">6497</span><span id="line-6497">        this.setReadsEnabled(true);</span>
+<span class="source-line-no">6498</span><span id="line-6498"></span>
+<span class="source-line-no">6499</span><span id="line-6499">        // C. Finally notify anyone waiting on memstore to clear:</span>
+<span class="source-line-no">6500</span><span id="line-6500">        // e.g. checkResources().</span>
+<span class="source-line-no">6501</span><span id="line-6501">        synchronized (this) {</span>
+<span class="source-line-no">6502</span><span id="line-6502">          notifyAll(); // FindBugs NN_NAKED_NOTIFY</span>
+<span class="source-line-no">6503</span><span id="line-6503">        }</span>
+<span class="source-line-no">6504</span><span id="line-6504">      }</span>
+<span class="source-line-no">6505</span><span id="line-6505">      logRegionFiles();</span>
+<span class="source-line-no">6506</span><span id="line-6506">    } finally {</span>
+<span class="source-line-no">6507</span><span id="line-6507">      closeRegionOperation(Operation.REPLAY_EVENT);</span>
+<span class="source-line-no">6508</span><span id="line-6508">    }</span>
+<span class="source-line-no">6509</span><span id="line-6509">  }</span>
 <span class="source-line-no">6510</span><span id="line-6510"></span>
-<span class="source-line-no">6511</span><span id="line-6511">          StoreContext storeContext = store.getStoreContext();</span>
-<span class="source-line-no">6512</span><span id="line-6512">          StoreFileTracker sft = StoreFileTrackerFactory.create(conf, false, storeContext);</span>
-<span class="source-line-no">6513</span><span id="line-6513"></span>
-<span class="source-line-no">6514</span><span id="line-6514">          List&lt;StoreFileInfo&gt; storeFiles = sft.load();</span>
-<span class="source-line-no">6515</span><span id="line-6515">          for (StoreFileInfo storeFileInfo : storeFiles) {</span>
-<span class="source-line-no">6516</span><span id="line-6516">            try {</span>
-<span class="source-line-no">6517</span><span id="line-6517">              store.bulkLoadHFile(storeFileInfo);</span>
-<span class="source-line-no">6518</span><span id="line-6518">            } catch (FileNotFoundException ex) {</span>
-<span class="source-line-no">6519</span><span id="line-6519">              LOG.warn(getRegionInfo().getEncodedName() + " : " + storeFileInfo.toString()</span>
-<span class="source-line-no">6520</span><span id="line-6520">                + " doesn't exist any more. Skip loading the file");</span>
-<span class="source-line-no">6521</span><span id="line-6521">            }</span>
-<span class="source-line-no">6522</span><span id="line-6522">          }</span>
-<span class="source-line-no">6523</span><span id="line-6523">        }</span>
-<span class="source-line-no">6524</span><span id="line-6524">      }</span>
-<span class="source-line-no">6525</span><span id="line-6525">      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {</span>
-<span class="source-line-no">6526</span><span id="line-6526">        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());</span>
-<span class="source-line-no">6527</span><span id="line-6527">      }</span>
-<span class="source-line-no">6528</span><span id="line-6528">    } finally {</span>
-<span class="source-line-no">6529</span><span id="line-6529">      closeBulkRegionOperation();</span>
-<span class="source-line-no">6530</span><span id="line-6530">    }</span>
-<span class="source-line-no">6531</span><span id="line-6531">  }</span>
-<span class="source-line-no">6532</span><span id="line-6532"></span>
-<span class="source-line-no">6533</span><span id="line-6533">  /**</span>
-<span class="source-line-no">6534</span><span id="line-6534">   * Replay the batch mutate for secondary replica.</span>
-<span class="source-line-no">6535</span><span id="line-6535">   * &lt;p/&gt;</span>
-<span class="source-line-no">6536</span><span id="line-6536">   * We will directly apply the cells to the memstore. This is because:</span>
-<span class="source-line-no">6537</span><span id="line-6537">   * &lt;ol&gt;</span>
-<span class="source-line-no">6538</span><span id="line-6538">   * &lt;li&gt;All the cells are gotten from {@link WALEdit}, so we only have {@link Put} and</span>
-<span class="source-line-no">6539</span><span id="line-6539">   * {@link Delete} here&lt;/li&gt;</span>
-<span class="source-line-no">6540</span><span id="line-6540">   * &lt;li&gt;The replay is single threaded, we do not need to acquire row lock, as the region is read</span>
-<span class="source-line-no">6541</span><span id="line-6541">   * only so no one else can write it.&lt;/li&gt;</span>
-<span class="source-line-no">6542</span><span id="line-6542">   * &lt;li&gt;We do not need to write WAL.&lt;/li&gt;</span>
-<span class="source-line-no">6543</span><span id="line-6543">   * &lt;li&gt;We will advance MVCC in the caller directly.&lt;/li&gt;</span>
-<span class="source-line-no">6544</span><span id="line-6544">   * &lt;/ol&gt;</span>
-<span class="source-line-no">6545</span><span id="line-6545">   */</span>
-<span class="source-line-no">6546</span><span id="line-6546">  private void replayWALBatchMutate(Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; family2Cells)</span>
-<span class="source-line-no">6547</span><span id="line-6547">    throws IOException {</span>
-<span class="source-line-no">6548</span><span id="line-6548">    startRegionOperation(Operation.REPLAY_BATCH_MUTATE);</span>
-<span class="source-line-no">6549</span><span id="line-6549">    try {</span>
-<span class="source-line-no">6550</span><span id="line-6550">      for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; entry : family2Cells.entrySet()) {</span>
-<span class="source-line-no">6551</span><span id="line-6551">        applyToMemStore(getStore(entry.getKey()), entry.getValue(), false, memStoreSizing);</span>
-<span class="source-line-no">6552</span><span id="line-6552">      }</span>
-<span class="source-line-no">6553</span><span id="line-6553">    } finally {</span>
-<span class="source-line-no">6554</span><span id="line-6554">      closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);</span>
-<span class="source-line-no">6555</span><span id="line-6555">    }</span>
-<span class="source-line-no">6556</span><span id="line-6556">  }</span>
-<span class="source-line-no">6557</span><span id="line-6557"></span>
-<span class="source-line-no">6558</span><span id="line-6558">  /**</span>
-<span class="source-line-no">6559</span><span id="line-6559">   * Replay the meta edits, i.e, flush marker, compaction marker, bulk load marker, region event</span>
-<span class="source-line-no">6560</span><span id="line-6560">   * marker, etc.</span>
-<span class="source-line-no">6561</span><span id="line-6561">   * &lt;p/&gt;</span>
-<span class="source-line-no">6562</span><span id="line-6562">   * For all events other than start flush, we will just call {@link #refreshStoreFiles()} as the</span>
-<span class="source-line-no">6563</span><span id="line-6563">   * logic is straight-forward and robust. For start flush, we need to snapshot the memstore, so</span>
-<span class="source-line-no">6564</span><span id="line-6564">   * later {@link #refreshStoreFiles()} call could drop the snapshot, otherwise we may run out of</span>
-<span class="source-line-no">6565</span><span id="line-6565">   * memory.</span>
-<span class="source-line-no">6566</span><span id="line-6566">   */</span>
-<span class="source-line-no">6567</span><span id="line-6567">  private void replayWALMetaEdit(Cell cell) throws IOException {</span>
-<span class="source-line-no">6568</span><span id="line-6568">    startRegionOperation(Operation.REPLAY_EVENT);</span>
-<span class="source-line-no">6569</span><span id="line-6569">    try {</span>
-<span class="source-line-no">6570</span><span id="line-6570">      FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(cell);</span>
-<span class="source-line-no">6571</span><span id="line-6571">      if (flushDesc != null) {</span>
-<span class="source-line-no">6572</span><span id="line-6572">        switch (flushDesc.getAction()) {</span>
-<span class="source-line-no">6573</span><span id="line-6573">          case START_FLUSH:</span>
-<span class="source-line-no">6574</span><span id="line-6574">            // for start flush, we need to take a snapshot of the current memstore</span>
-<span class="source-line-no">6575</span><span id="line-6575">            synchronized (writestate) {</span>
-<span class="source-line-no">6576</span><span id="line-6576">              if (!writestate.flushing) {</span>
-<span class="source-line-no">6577</span><span id="line-6577">                this.writestate.flushing = true;</span>
-<span class="source-line-no">6578</span><span id="line-6578">              } else {</span>
-<span class="source-line-no">6579</span><span id="line-6579">                // usually this should not happen but let's make the code more robust, it is not a</span>
-<span class="source-line-no">6580</span><span id="line-6580">                // big deal to just ignore it, the refreshStoreFiles call should have the ability to</span>
-<span class="source-line-no">6581</span><span id="line-6581">                // clean up the inconsistent state.</span>
-<span class="source-line-no">6582</span><span id="line-6582">                LOG.debug("NOT flushing {} as already flushing", getRegionInfo());</span>
-<span class="source-line-no">6583</span><span id="line-6583">                break;</span>
-<span class="source-line-no">6584</span><span id="line-6584">              }</span>
-<span class="source-line-no">6585</span><span id="line-6585">            }</span>
-<span class="source-line-no">6586</span><span id="line-6586">            MonitoredTask status =</span>
-<span class="source-line-no">6587</span><span id="line-6587">              TaskMonitor.get().createStatus("Preparing flush " + getRegionInfo());</span>
-<span class="source-line-no">6588</span><span id="line-6588">            Collection&lt;HStore&gt; storesToFlush = getStoresToFlush(flushDesc);</span>
-<span class="source-line-no">6589</span><span id="line-6589">            try {</span>
-<span class="source-line-no">6590</span><span id="line-6590">              PrepareFlushResult prepareResult =</span>
-<span class="source-line-no">6591</span><span id="line-6591">                internalPrepareFlushCache(null, flushDesc.getFlushSequenceNumber(), storesToFlush,</span>
-<span class="source-line-no">6592</span><span id="line-6592">                  status, false, FlushLifeCycleTracker.DUMMY);</span>
-<span class="source-line-no">6593</span><span id="line-6593">              if (prepareResult.result == null) {</span>
-<span class="source-line-no">6594</span><span id="line-6594">                // save the PrepareFlushResult so that we can use it later from commit flush</span>
-<span class="source-line-no">6595</span><span id="line-6595">                this.prepareFlushResult = prepareResult;</span>
-<span class="source-line-no">6596</span><span id="line-6596">                status.markComplete("Flush prepare successful");</span>
-<span class="source-line-no">6597</span><span id="line-6597">                if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">6598</span><span id="line-6598">                  LOG.debug("{} prepared flush with seqId: {}", getRegionInfo(),</span>
-<span class="source-line-no">6599</span><span id="line-6599">                    flushDesc.getFlushSequenceNumber());</span>
-<span class="source-line-no">6600</span><span id="line-6600">                }</span>
-<span class="source-line-no">6601</span><span id="line-6601">              } else {</span>
-<span class="source-line-no">6602</span><span id="line-6602">                // special case empty memstore. We will still save the flush result in this case,</span>
-<span class="source-line-no">6603</span><span id="line-6603">                // since our memstore is empty, but the primary is still flushing</span>
-<span class="source-line-no">6604</span><span id="line-6604">                if (</span>
-<span class="source-line-no">6605</span><span id="line-6605">                  prepareResult.getResult().getResult()</span>
-<span class="source-line-no">6606</span><span id="line-6606">                      == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY</span>
-<span class="source-line-no">6607</span><span id="line-6607">                ) {</span>
-<span class="source-line-no">6608</span><span id="line-6608">                  this.prepareFlushResult = prepareResult;</span>
-<span class="source-line-no">6609</span><span id="line-6609">                  if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">6610</span><span id="line-6610">                    LOG.debug("{} prepared empty flush with seqId: {}", getRegionInfo(),</span>
-<span class="source-line-no">6611</span><span id="line-6611">                      flushDesc.getFlushSequenceNumber());</span>
-<span class="source-line-no">6612</span><span id="line-6612">                  }</span>
-<span class="source-line-no">6613</span><span id="line-6613">                }</span>
-<span class="source-line-no">6614</span><span id="line-6614">                status.abort("Flush prepare failed with " + prepareResult.result);</span>
-<span class="source-line-no">6615</span><span id="line-6615">                // nothing much to do. prepare flush failed because of some reason.</span>
-<span class="source-line-no">6616</span><span id="line-6616">              }</span>
-<span class="source-line-no">6617</span><span id="line-6617">            } finally {</span>
-<span class="source-line-no">6618</span><span id="line-6618">              status.cleanup();</span>
-<span class="source-line-no">6619</span><span id="line-6619">            }</span>
-<span class="source-line-no">6620</span><span id="line-6620">            break;</span>
-<span class="source-line-no">6621</span><span id="line-6621">          case ABORT_FLUSH:</span>
-<span class="source-line-no">6622</span><span id="line-6622">            // do nothing, an abort flush means the source region server will crash itself, after</span>
-<span class="source-line-no">6623</span><span id="line-6623">            // the primary region online, it will send us an open region marker, then we can clean</span>
-<span class="source-line-no">6624</span><span id="line-6624">            // up the memstore.</span>
-<span class="source-line-no">6625</span><span id="line-6625">            synchronized (writestate) {</span>
-<span class="source-line-no">6626</span><span id="line-6626">              writestate.flushing = false;</span>
-<span class="source-line-no">6627</span><span id="line-6627">            }</span>
-<span class="source-line-no">6628</span><span id="line-6628">            break;</span>
-<span class="source-line-no">6629</span><span id="line-6629">          case COMMIT_FLUSH:</span>
-<span class="source-line-no">6630</span><span id="line-6630">          case CANNOT_FLUSH:</span>
-<span class="source-line-no">6631</span><span id="line-6631">            // just call refreshStoreFiles</span>
-<span class="source-line-no">6632</span><span id="line-6632">            refreshStoreFiles();</span>
-<span class="source-line-no">6633</span><span id="line-6633">            logRegionFiles();</span>
-<span class="source-line-no">6634</span><span id="line-6634">            synchronized (writestate) {</span>
-<span class="source-line-no">6635</span><span id="line-6635">              writestate.flushing = false;</span>
-<span class="source-line-no">6636</span><span id="line-6636">            }</span>
-<span class="source-line-no">6637</span><span id="line-6637">            break;</span>
-<span class="source-line-no">6638</span><span id="line-6638">          default:</span>
-<span class="source-line-no">6639</span><span id="line-6639">            LOG.warn("{} received a flush event with unknown action: {}", getRegionInfo(),</span>
-<span class="source-line-no">6640</span><span id="line-6640">              TextFormat.shortDebugString(flushDesc));</span>
-<span class="source-line-no">6641</span><span id="line-6641">        }</span>
-<span class="source-line-no">6642</span><span id="line-6642">      } else {</span>
-<span class="source-line-no">6643</span><span id="line-6643">        // for all other region events, we will do a refreshStoreFiles</span>
-<span class="source-line-no">6644</span><span id="line-6644">        refreshStoreFiles();</span>
-<span class="source-line-no">6645</span><span id="line-6645">        logRegionFiles();</span>
-<span class="source-line-no">6646</span><span id="line-6646">      }</span>
-<span class="source-line-no">6647</span><span id="line-6647">    } finally {</span>
-<span class="source-line-no">6648</span><span id="line-6648">      closeRegionOperation(Operation.REPLAY_EVENT);</span>
-<span class="source-line-no">6649</span><span id="line-6649">    }</span>
-<span class="source-line-no">6650</span><span id="line-6650">  }</span>
-<span class="source-line-no">6651</span><span id="line-6651"></span>
-<span class="source-line-no">6652</span><span id="line-6652">  /**</span>
-<span class="source-line-no">6653</span><span id="line-6653">   * Replay remote wal entry sent by primary replica.</span>
-<span class="source-line-no">6654</span><span id="line-6654">   * &lt;p/&gt;</span>
-<span class="source-line-no">6655</span><span id="line-6655">   * Should only call this method on secondary replicas.</span>
-<span class="source-line-no">6656</span><span id="line-6656">   */</span>
-<span class="source-line-no">6657</span><span id="line-6657">  void replayWALEntry(WALEntry entry, CellScanner cells) throws IOException {</span>
-<span class="source-line-no">6658</span><span id="line-6658">    long timeout = -1L;</span>
-<span class="source-line-no">6659</span><span id="line-6659">    Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();</span>
-<span class="source-line-no">6660</span><span id="line-6660">    if (call.isPresent()) {</span>
-<span class="source-line-no">6661</span><span id="line-6661">      long deadline = call.get().getDeadline();</span>
-<span class="source-line-no">6662</span><span id="line-6662">      if (deadline &lt; Long.MAX_VALUE) {</span>
-<span class="source-line-no">6663</span><span id="line-6663">        timeout = deadline - EnvironmentEdgeManager.currentTime();</span>
-<span class="source-line-no">6664</span><span id="line-6664">        if (timeout &lt;= 0) {</span>
-<span class="source-line-no">6665</span><span id="line-6665">          throw new TimeoutIOException("Timeout while replaying edits for " + getRegionInfo());</span>
-<span class="source-line-no">6666</span><span id="line-6666">        }</span>
-<span class="source-line-no">6667</span><span id="line-6667">      }</span>
-<span class="source-line-no">6668</span><span id="line-6668">    }</span>
-<span class="source-line-no">6669</span><span id="line-6669">    if (timeout &gt; 0) {</span>
-<span class="source-line-no">6670</span><span id="line-6670">      try {</span>
-<span class="source-line-no">6671</span><span id="line-6671">        if (!replayLock.tryLock(timeout, TimeUnit.MILLISECONDS)) {</span>
-<span class="source-line-no">6672</span><span id="line-6672">          throw new TimeoutIOException(</span>
-<span class="source-line-no">6673</span><span id="line-6673">            "Timeout while waiting for lock when replaying edits for " + getRegionInfo());</span>
-<span class="source-line-no">6674</span><span id="line-6674">        }</span>
-<span class="source-line-no">6675</span><span id="line-6675">      } catch (InterruptedException e) {</span>
-<span class="source-line-no">6676</span><span id="line-6676">        throw throwOnInterrupt(e);</span>
-<span class="source-line-no">6677</span><span id="line-6677">      }</span>
-<span class="source-line-no">6678</span><span id="line-6678">    } else {</span>
-<span class="source-line-no">6679</span><span id="line-6679">      replayLock.lock();</span>
-<span class="source-line-no">6680</span><span id="line-6680">    }</span>
-<span class="source-line-no">6681</span><span id="line-6681">    try {</span>
-<span class="source-line-no">6682</span><span id="line-6682">      int count = entry.getAssociatedCellCount();</span>
-<span class="source-line-no">6683</span><span id="line-6683">      long sequenceId = entry.getKey().getLogSequenceNumber();</span>
-<span class="source-line-no">6684</span><span id="line-6684">      if (lastReplayedSequenceId &gt;= sequenceId) {</span>
-<span class="source-line-no">6685</span><span id="line-6685">        // we have already replayed this edit, skip</span>
-<span class="source-line-no">6686</span><span id="line-6686">        // remember to advance the CellScanner, as we may have multiple WALEntries, we may still</span>
-<span class="source-line-no">6687</span><span id="line-6687">        // need apply later WALEntries</span>
-<span class="source-line-no">6688</span><span id="line-6688">        for (int i = 0; i &lt; count; i++) {</span>
-<span class="source-line-no">6689</span><span id="line-6689">          // Throw index out of bounds if our cell count is off</span>
-<span class="source-line-no">6690</span><span id="line-6690">          if (!cells.advance()) {</span>
-<span class="source-line-no">6691</span><span id="line-6691">            throw new ArrayIndexOutOfBoundsException("Expected=" + count + ", index=" + i);</span>
-<span class="source-line-no">6692</span><span id="line-6692">          }</span>
-<span class="source-line-no">6693</span><span id="line-6693">        }</span>
-<span class="source-line-no">6694</span><span id="line-6694">        return;</span>
-<span class="source-line-no">6695</span><span id="line-6695">      }</span>
-<span class="source-line-no">6696</span><span id="line-6696">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; family2Cells = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
-<span class="source-line-no">6697</span><span id="line-6697">      for (int i = 0; i &lt; count; i++) {</span>
-<span class="source-line-no">6698</span><span id="line-6698">        // Throw index out of bounds if our cell count is off</span>
-<span class="source-line-no">6699</span><span id="line-6699">        if (!cells.advance()) {</span>
-<span class="source-line-no">6700</span><span id="line-6700">          throw new ArrayIndexOutOfBoundsException("Expected=" + count + ", index=" + i);</span>
-<span class="source-line-no">6701</span><span id="line-6701">        }</span>
-<span class="source-line-no">6702</span><span id="line-6702">        Cell c = cells.current();</span>
-<span class="source-line-no">6703</span><span id="line-6703">        assert c instanceof ExtendedCell;</span>
-<span class="source-line-no">6704</span><span id="line-6704">        ExtendedCell cell = (ExtendedCell) c;</span>
-<span class="source-line-no">6705</span><span id="line-6705">        if (WALEdit.isMetaEditFamily(cell)) {</span>
-<span class="source-line-no">6706</span><span id="line-6706">          // If there is meta edit, i.e, we have done flush/compaction/open, then we need to apply</span>
-<span class="source-line-no">6707</span><span id="line-6707">          // the previous cells first, and then replay the special meta edit. The meta edit is like</span>
-<span class="source-line-no">6708</span><span id="line-6708">          // a barrier, We need to keep the order. For example, the flush marker will contain a</span>
-<span class="source-line-no">6709</span><span id="line-6709">          // flush sequence number, which makes us possible to drop memstore content, but if we</span>
-<span class="source-line-no">6710</span><span id="line-6710">          // apply some edits which have greater sequence id first, then we can not drop the</span>
-<span class="source-line-no">6711</span><span id="line-6711">          // memstore content when replaying the flush marker, which is not good as we could run out</span>
-<span class="source-line-no">6712</span><span id="line-6712">          // of memory.</span>
-<span class="source-line-no">6713</span><span id="line-6713">          // And usually, a meta edit will have a special WALEntry for it, so this is just a safe</span>
-<span class="source-line-no">6714</span><span id="line-6714">          // guard logic to make sure we do not break things in the worst case.</span>
-<span class="source-line-no">6715</span><span id="line-6715">          if (!family2Cells.isEmpty()) {</span>
-<span class="source-line-no">6716</span><span id="line-6716">            replayWALBatchMutate(family2Cells);</span>
-<span class="source-line-no">6717</span><span id="line-6717">            family2Cells.clear();</span>
-<span class="source-line-no">6718</span><span id="line-6718">          }</span>
-<span class="source-line-no">6719</span><span id="line-6719">          replayWALMetaEdit(cell);</span>
-<span class="source-line-no">6720</span><span id="line-6720">        } else {</span>
-<span class="source-line-no">6721</span><span id="line-6721">          family2Cells.computeIfAbsent(CellUtil.cloneFamily(cell), k -&gt; new ArrayList&lt;&gt;())</span>
-<span class="source-line-no">6722</span><span id="line-6722">            .add(cell);</span>
-<span class="source-line-no">6723</span><span id="line-6723">        }</span>
-<span class="source-line-no">6724</span><span id="line-6724">      }</span>
-<span class="source-line-no">6725</span><span id="line-6725">      // do not forget to apply the remaining cells</span>
-<span class="source-line-no">6726</span><span id="line-6726">      if (!family2Cells.isEmpty()) {</span>
-<span class="source-line-no">6727</span><span id="line-6727">        replayWALBatchMutate(family2Cells);</span>
-<span class="source-line-no">6728</span><span id="line-6728">      }</span>
-<span class="source-line-no">6729</span><span id="line-6729">      mvcc.advanceTo(sequenceId);</span>
-<span class="source-line-no">6730</span><span id="line-6730">      lastReplayedSequenceId = sequenceId;</span>
-<span class="source-line-no">6731</span><span id="line-6731">    } finally {</span>
-<span class="source-line-no">6732</span><span id="line-6732">      replayLock.unlock();</span>
-<span class="source-line-no">6733</span><span id="line-6733">    }</span>
-<span class="source-line-no">6734</span><span id="line-6734">  }</span>
-<span class="source-line-no">6735</span><span id="line-6735"></span>
-<span class="source-line-no">6736</span><span id="line-6736">  /**</span>
-<span class="source-line-no">6737</span><span id="line-6737">   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult</span>
-<span class="source-line-no">6738</span><span id="line-6738">   */</span>
-<span class="source-line-no">6739</span><span id="line-6739">  private void dropPrepareFlushIfPossible() {</span>
-<span class="source-line-no">6740</span><span id="line-6740">    if (writestate.flushing) {</span>
-<span class="source-line-no">6741</span><span id="line-6741">      boolean canDrop = true;</span>
-<span class="source-line-no">6742</span><span id="line-6742">      if (prepareFlushResult.storeFlushCtxs != null) {</span>
-<span class="source-line-no">6743</span><span id="line-6743">        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs</span>
-<span class="source-line-no">6744</span><span id="line-6744">          .entrySet()) {</span>
-<span class="source-line-no">6745</span><span id="line-6745">          HStore store = getStore(entry.getKey());</span>
-<span class="source-line-no">6746</span><span id="line-6746">          if (store == null) {</span>
-<span class="source-line-no">6747</span><span id="line-6747">            continue;</span>
-<span class="source-line-no">6748</span><span id="line-6748">          }</span>
-<span class="source-line-no">6749</span><span id="line-6749">          if (store.getSnapshotSize().getDataSize() &gt; 0) {</span>
-<span class="source-line-no">6750</span><span id="line-6750">            canDrop = false;</span>
-<span class="source-line-no">6751</span><span id="line-6751">            break;</span>
-<span class="source-line-no">6752</span><span id="line-6752">          }</span>
-<span class="source-line-no">6753</span><span id="line-6753">        }</span>
-<span class="source-line-no">6754</span><span id="line-6754">      }</span>
-<span class="source-line-no">6755</span><span id="line-6755"></span>
-<span class="source-line-no">6756</span><span id="line-6756">      // this means that all the stores in the region has finished flushing, but the WAL marker</span>
-<span class="source-line-no">6757</span><span id="line-6757">      // may not have been written or we did not receive it yet.</span>
-<span class="source-line-no">6758</span><span id="line-6758">      if (canDrop) {</span>
-<span class="source-line-no">6759</span><span id="line-6759">        writestate.flushing = false;</span>
-<span class="source-line-no">6760</span><span id="line-6760">        this.prepareFlushResult = null;</span>
-<span class="source-line-no">6761</span><span id="line-6761">      }</span>
-<span class="source-line-no">6762</span><span id="line-6762">    }</span>
-<span class="source-line-no">6763</span><span id="line-6763">  }</span>
-<span class="source-line-no">6764</span><span id="line-6764"></span>
-<span class="source-line-no">6765</span><span id="line-6765">  @Override</span>
-<span class="source-line-no">6766</span><span id="line-6766">  public boolean refreshStoreFiles() throws IOException {</span>
-<span class="source-line-no">6767</span><span id="line-6767">    return refreshStoreFiles(false);</span>
-<span class="source-line-no">6768</span><span id="line-6768">  }</span>
-<span class="source-line-no">6769</span><span id="line-6769"></span>
-<span class="source-line-no">6770</span><span id="line-6770">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",</span>
-<span class="source-line-no">6771</span><span id="line-6771">      justification = "Notify is about post replay. Intentional")</span>
-<span class="source-line-no">6772</span><span id="line-6772">  protected boolean refreshStoreFiles(boolean force) throws IOException {</span>
-<span class="source-line-no">6773</span><span id="line-6773">    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
-<span class="source-line-no">6774</span><span id="line-6774">      return false; // if primary nothing to do</span>
-<span class="source-line-no">6775</span><span id="line-6775">    }</span>
-<span class="source-line-no">6776</span><span id="line-6776"></span>
-<span class="source-line-no">6777</span><span id="line-6777">    if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">6778</span><span id="line-6778">      LOG.debug(getRegionInfo().getEncodedName() + " : "</span>
-<span class="source-line-no">6779</span><span id="line-6779">        + "Refreshing store files to see whether we can free up memstore");</span>
-<span class="source-line-no">6780</span><span id="line-6780">    }</span>
-<span class="source-line-no">6781</span><span id="line-6781"></span>
-<span class="source-line-no">6782</span><span id="line-6782">    long totalFreedDataSize = 0;</span>
-<span class="source-line-no">6783</span><span id="line-6783"></span>
-<span class="source-line-no">6784</span><span id="line-6784">    long smallestSeqIdInStores = Long.MAX_VALUE;</span>
-<span class="source-line-no">6785</span><span id="line-6785"></span>
-<span class="source-line-no">6786</span><span id="line-6786">    startRegionOperation(); // obtain region close lock</span>
-<span class="source-line-no">6787</span><span id="line-6787">    try {</span>
-<span class="source-line-no">6788</span><span id="line-6788">      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();</span>
-<span class="source-line-no">6789</span><span id="line-6789">      synchronized (writestate) {</span>
-<span class="source-line-no">6790</span><span id="line-6790">        for (HStore store : stores.values()) {</span>
-<span class="source-line-no">6791</span><span id="line-6791">          // TODO: some stores might see new data from flush, while others do not which</span>
-<span class="source-line-no">6792</span><span id="line-6792">          // MIGHT break atomic edits across column families.</span>
-<span class="source-line-no">6793</span><span id="line-6793">          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);</span>
-<span class="source-line-no">6794</span><span id="line-6794"></span>
-<span class="source-line-no">6795</span><span id="line-6795">          // refresh the store files. This is similar to observing a region open wal marker.</span>
-<span class="source-line-no">6796</span><span id="line-6796">          store.refreshStoreFiles();</span>
-<span class="source-line-no">6797</span><span id="line-6797"></span>
-<span class="source-line-no">6798</span><span id="line-6798">          long storeSeqId = store.getMaxSequenceId().orElse(0L);</span>
-<span class="source-line-no">6799</span><span id="line-6799">          if (storeSeqId &lt; smallestSeqIdInStores) {</span>
-<span class="source-line-no">6800</span><span id="line-6800">            smallestSeqIdInStores = storeSeqId;</span>
-<span class="source-line-no">6801</span><span id="line-6801">          }</span>
-<span class="source-line-no">6802</span><span id="line-6802"></span>
-<span class="source-line-no">6803</span><span id="line-6803">          // see whether we can drop the memstore or the snapshot</span>
-<span class="source-line-no">6804</span><span id="line-6804">          if (storeSeqId &gt; maxSeqIdBefore) {</span>
-<span class="source-line-no">6805</span><span id="line-6805">            if (writestate.flushing) {</span>
-<span class="source-line-no">6806</span><span id="line-6806">              // only drop memstore snapshots if they are smaller than last flush for the store</span>
-<span class="source-line-no">6807</span><span id="line-6807">              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {</span>
-<span class="source-line-no">6808</span><span id="line-6808">                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null</span>
-<span class="source-line-no">6809</span><span id="line-6809">                  ? null</span>
-<span class="source-line-no">6810</span><span id="line-6810">                  : this.prepareFlushResult.storeFlushCtxs</span>
-<span class="source-line-no">6811</span><span id="line-6811">                    .get(store.getColumnFamilyDescriptor().getName());</span>
-<span class="source-line-no">6812</span><span id="line-6812">                if (ctx != null) {</span>
-<span class="source-line-no">6813</span><span id="line-6813">                  MemStoreSize mss = store.getFlushableSize();</span>
-<span class="source-line-no">6814</span><span id="line-6814">                  ctx.abort();</span>
-<span class="source-line-no">6815</span><span id="line-6815">                  this.decrMemStoreSize(mss);</span>
-<span class="source-line-no">6816</span><span id="line-6816">                  this.prepareFlushResult.storeFlushCtxs</span>
-<span class="source-line-no">6817</span><span id="line-6817">                    .remove(store.getColumnFamilyDescriptor().getName());</span>
-<span class="source-line-no">6818</span><span id="line-6818">                  totalFreedDataSize += mss.getDataSize();</span>
-<span class="source-line-no">6819</span><span id="line-6819">                }</span>
-<span class="source-line-no">6820</span><span id="line-6820">              }</span>
-<span class="source-line-no">6821</span><span id="line-6821">            }</span>
-<span class="source-line-no">6822</span><span id="line-6822"></span>
-<span class="source-line-no">6823</span><span id="line-6823">            map.put(store, storeSeqId);</span>
-<span class="source-line-no">6824</span><span id="line-6824">          }</span>
-<span class="source-line-no">6825</span><span id="line-6825">        }</span>
-<span class="source-line-no">6826</span><span id="line-6826"></span>
-<span class="source-line-no">6827</span><span id="line-6827">        // if all stores ended up dropping their snapshots, we can safely drop the</span>
-<span class="source-line-no">6828</span><span id="line-6828">        // prepareFlushResult</span>
-<span class="source-line-no">6829</span><span id="line-6829">        dropPrepareFlushIfPossible();</span>
-<span class="source-line-no">6830</span><span id="line-6830"></span>
-<span class="source-line-no">6831</span><span id="line-6831">        // advance the mvcc read point so that the new flushed files are visible.</span>
-<span class="source-line-no">6832</span><span id="line-6832">        // either greater than flush seq number or they were already picked up via flush.</span>
-<span class="source-line-no">6833</span><span id="line-6833">        for (HStore s : stores.values()) {</span>
-<span class="source-line-no">6834</span><span id="line-6834">          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));</span>
-<span class="source-line-no">6835</span><span id="line-6835">        }</span>
-<span class="source-line-no">6836</span><span id="line-6836"></span>
-<span class="source-line-no">6837</span><span id="line-6837">        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely</span>
-<span class="source-line-no">6838</span><span id="line-6838">        // skip all edits that are to be replayed in the future with that has a smaller seqId</span>
-<span class="source-line-no">6839</span><span id="line-6839">        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits</span>
-<span class="source-line-no">6840</span><span id="line-6840">        // that we have picked the flush files for</span>
-<span class="source-line-no">6841</span><span id="line-6841">        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {</span>
-<span class="source-line-no">6842</span><span id="line-6842">          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;</span>
-<span class="source-line-no">6843</span><span id="line-6843">        }</span>
-<span class="source-line-no">6844</span><span id="line-6844">      }</span>
-<span class="source-line-no">6845</span><span id="line-6845">      if (!map.isEmpty()) {</span>
-<span class="source-line-no">6846</span><span id="line-6846">        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {</span>
-<span class="source-line-no">6847</span><span id="line-6847">          // Drop the memstore contents if they are now smaller than the latest seen flushed file</span>
-<span class="source-line-no">6848</span><span id="line-6848">          totalFreedDataSize +=</span>
-<span class="source-line-no">6849</span><span id="line-6849">            dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey()).getDataSize();</span>
-<span class="source-line-no">6850</span><span id="line-6850">        }</span>
-<span class="source-line-no">6851</span><span id="line-6851">      }</span>
-<span class="source-line-no">6852</span><span id="line-6852">      // C. Finally notify anyone waiting on memstore to clear:</span>
-<span class="source-line-no">6853</span><span id="line-6853">      // e.g. checkResources().</span>
-<span class="source-line-no">6854</span><span id="line-6854">      synchronized (this) {</span>
-<span class="source-line-no">6855</span><span id="line-6855">        notifyAll(); // FindBugs NN_NAKED_NOTIFY</span>
-<span class="source-line-no">6856</span><span id="line-6856">      }</span>
-<span class="source-line-no">6857</span><span id="line-6857">      return totalFreedDataSize &gt; 0;</span>
-<span class="source-line-no">6858</span><span id="line-6858">    } finally {</span>
-<span class="source-line-no">6859</span><span id="line-6859">      closeRegionOperation();</span>
-<span class="source-line-no">6860</span><span id="line-6860">    }</span>
-<span class="source-line-no">6861</span><span id="line-6861">  }</span>
-<span class="source-line-no">6862</span><span id="line-6862"></span>
-<span class="source-line-no">6863</span><span id="line-6863">  private void logRegionFiles() {</span>
-<span class="source-line-no">6864</span><span id="line-6864">    if (LOG.isTraceEnabled()) {</span>
-<span class="source-line-no">6865</span><span id="line-6865">      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");</span>
-<span class="source-line-no">6866</span><span id="line-6866">      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)</span>
-<span class="source-line-no">6867</span><span id="line-6867">        .flatMap(s -&gt; s.getStorefiles().stream())</span>
-<span class="source-line-no">6868</span><span id="line-6868">        .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));</span>
-<span class="source-line-no">6869</span><span id="line-6869">    }</span>
-<span class="source-line-no">6870</span><span id="line-6870">  }</span>
-<span class="source-line-no">6871</span><span id="line-6871"></span>
-<span class="source-line-no">6872</span><span id="line-6872">  /**</span>
-<span class="source-line-no">6873</span><span id="line-6873">   * Checks whether the given regionName is either equal to our region, or that the regionName is</span>
-<span class="source-line-no">6874</span><span id="line-6874">   * the primary region to our corresponding range for the secondary replica.</span>
-<span class="source-line-no">6875</span><span id="line-6875">   */</span>
-<span class="source-line-no">6876</span><span id="line-6876">  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)</span>
-<span class="source-line-no">6877</span><span id="line-6877">    throws WrongRegionException {</span>
-<span class="source-line-no">6878</span><span id="line-6878">    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {</span>
-<span class="source-line-no">6879</span><span id="line-6879">      return;</span>
-<span class="source-line-no">6880</span><span id="line-6880">    }</span>
-<span class="source-line-no">6881</span><span id="line-6881"></span>
-<span class="source-line-no">6882</span><span id="line-6882">    if (</span>
-<span class="source-line-no">6883</span><span id="line-6883">      !RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())</span>
-<span class="source-line-no">6884</span><span id="line-6884">        &amp;&amp; Bytes.equals(encodedRegionName, this.fs.getRegionInfoForFS().getEncodedNameAsBytes())</span>
-<span class="source-line-no">6885</span><span id="line-6885">    ) {</span>
-<span class="source-line-no">6886</span><span id="line-6886">      return;</span>
-<span class="source-line-no">6887</span><span id="line-6887">    }</span>
-<span class="source-line-no">6888</span><span id="line-6888"></span>
-<span class="source-line-no">6889</span><span id="line-6889">    throw new WrongRegionException(</span>
-<span class="source-line-no">6890</span><span id="line-6890">      exceptionMsg + payload + " targetted for region " + Bytes.toStringBinary(encodedRegionName)</span>
-<span class="source-line-no">6891</span><span id="line-6891">        + " does not match this region: " + this.getRegionInfo());</span>
-<span class="source-line-no">6892</span><span id="line-6892">  }</span>
+<span class="source-line-no">6511</span><span id="line-6511">  /**</span>
+<span class="source-line-no">6512</span><span id="line-6512">   * @deprecated Since 3.0.0, will be removed in 4.0.0. Only for keep compatibility for old region</span>
+<span class="source-line-no">6513</span><span id="line-6513">   *             replica implementation.</span>
+<span class="source-line-no">6514</span><span id="line-6514">   */</span>
+<span class="source-line-no">6515</span><span id="line-6515">  @Deprecated</span>
+<span class="source-line-no">6516</span><span id="line-6516">  void replayWALBulkLoadEventMarker(WALProtos.BulkLoadDescriptor bulkLoadEvent) throws IOException {</span>
+<span class="source-line-no">6517</span><span id="line-6517">    checkTargetRegion(bulkLoadEvent.getEncodedRegionName().toByteArray(),</span>
+<span class="source-line-no">6518</span><span id="line-6518">      "BulkLoad marker from WAL ", bulkLoadEvent);</span>
+<span class="source-line-no">6519</span><span id="line-6519"></span>
+<span class="source-line-no">6520</span><span id="line-6520">    if (ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
+<span class="source-line-no">6521</span><span id="line-6521">      return; // if primary nothing to do</span>
+<span class="source-line-no">6522</span><span id="line-6522">    }</span>
+<span class="source-line-no">6523</span><span id="line-6523"></span>
+<span class="source-line-no">6524</span><span id="line-6524">    if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">6525</span><span id="line-6525">      LOG.debug(getRegionInfo().getEncodedName() + " : " + "Replaying bulkload event marker "</span>
+<span class="source-line-no">6526</span><span id="line-6526">        + TextFormat.shortDebugString(bulkLoadEvent));</span>
+<span class="source-line-no">6527</span><span id="line-6527">    }</span>
+<span class="source-line-no">6528</span><span id="line-6528">    // check if multiple families involved</span>
+<span class="source-line-no">6529</span><span id="line-6529">    boolean multipleFamilies = false;</span>
+<span class="source-line-no">6530</span><span id="line-6530">    byte[] family = null;</span>
+<span class="source-line-no">6531</span><span id="line-6531">    for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {</span>
+<span class="source-line-no">6532</span><span id="line-6532">      byte[] fam = storeDescriptor.getFamilyName().toByteArray();</span>
+<span class="source-line-no">6533</span><span id="line-6533">      if (family == null) {</span>
+<span class="source-line-no">6534</span><span id="line-6534">        family = fam;</span>
+<span class="source-line-no">6535</span><span id="line-6535">      } else if (!Bytes.equals(family, fam)) {</span>
+<span class="source-line-no">6536</span><span id="line-6536">        multipleFamilies = true;</span>
+<span class="source-line-no">6537</span><span id="line-6537">        break;</span>
+<span class="source-line-no">6538</span><span id="line-6538">      }</span>
+<span class="source-line-no">6539</span><span id="line-6539">    }</span>
+<span class="source-line-no">6540</span><span id="line-6540"></span>
+<span class="source-line-no">6541</span><span id="line-6541">    startBulkRegionOperation(multipleFamilies);</span>
+<span class="source-line-no">6542</span><span id="line-6542">    try {</span>
+<span class="source-line-no">6543</span><span id="line-6543">      // we will use writestate as a coarse-grain lock for all the replay events</span>
+<span class="source-line-no">6544</span><span id="line-6544">      synchronized (writestate) {</span>
+<span class="source-line-no">6545</span><span id="line-6545">        // Replication can deliver events out of order when primary region moves or the region</span>
+<span class="source-line-no">6546</span><span id="line-6546">        // server crashes, since there is no coordination between replication of different wal files</span>
+<span class="source-line-no">6547</span><span id="line-6547">        // belonging to different region servers. We have to safe guard against this case by using</span>
+<span class="source-line-no">6548</span><span id="line-6548">        // region open event's seqid. Since this is the first event that the region puts (after</span>
+<span class="source-line-no">6549</span><span id="line-6549">        // possibly flushing recovered.edits), after seeing this event, we can ignore every edit</span>
+<span class="source-line-no">6550</span><span id="line-6550">        // smaller than this seqId</span>
+<span class="source-line-no">6551</span><span id="line-6551">        if (</span>
+<span class="source-line-no">6552</span><span id="line-6552">          bulkLoadEvent.getBulkloadSeqNum() &gt;= 0</span>
+<span class="source-line-no">6553</span><span id="line-6553">            &amp;&amp; this.lastReplayedOpenRegionSeqId &gt;= bulkLoadEvent.getBulkloadSeqNum()</span>
+<span class="source-line-no">6554</span><span id="line-6554">        ) {</span>
+<span class="source-line-no">6555</span><span id="line-6555">          LOG.warn(getRegionInfo().getEncodedName() + " : " + "Skipping replaying bulkload event :"</span>
+<span class="source-line-no">6556</span><span id="line-6556">            + TextFormat.shortDebugString(bulkLoadEvent)</span>
+<span class="source-line-no">6557</span><span id="line-6557">            + " because its sequence id is smaller than this region's lastReplayedOpenRegionSeqId"</span>
+<span class="source-line-no">6558</span><span id="line-6558">            + " =" + lastReplayedOpenRegionSeqId);</span>
+<span class="source-line-no">6559</span><span id="line-6559"></span>
+<span class="source-line-no">6560</span><span id="line-6560">          return;</span>
+<span class="source-line-no">6561</span><span id="line-6561">        }</span>
+<span class="source-line-no">6562</span><span id="line-6562"></span>
+<span class="source-line-no">6563</span><span id="line-6563">        for (StoreDescriptor storeDescriptor : bulkLoadEvent.getStoresList()) {</span>
+<span class="source-line-no">6564</span><span id="line-6564">          // stores of primary may be different now</span>
+<span class="source-line-no">6565</span><span id="line-6565">          family = storeDescriptor.getFamilyName().toByteArray();</span>
+<span class="source-line-no">6566</span><span id="line-6566">          HStore store = getStore(family);</span>
+<span class="source-line-no">6567</span><span id="line-6567">          if (store == null) {</span>
+<span class="source-line-no">6568</span><span id="line-6568">            LOG.warn(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6569</span><span id="line-6569">              + "Received a bulk load marker from primary, but the family is not found. "</span>
+<span class="source-line-no">6570</span><span id="line-6570">              + "Ignoring. StoreDescriptor:" + storeDescriptor);</span>
+<span class="source-line-no">6571</span><span id="line-6571">            continue;</span>
+<span class="source-line-no">6572</span><span id="line-6572">          }</span>
+<span class="source-line-no">6573</span><span id="line-6573"></span>
+<span class="source-line-no">6574</span><span id="line-6574">          StoreContext storeContext = store.getStoreContext();</span>
+<span class="source-line-no">6575</span><span id="line-6575">          StoreFileTracker sft = StoreFileTrackerFactory.create(conf, false, storeContext);</span>
+<span class="source-line-no">6576</span><span id="line-6576"></span>
+<span class="source-line-no">6577</span><span id="line-6577">          List&lt;StoreFileInfo&gt; storeFiles = sft.load();</span>
+<span class="source-line-no">6578</span><span id="line-6578">          for (StoreFileInfo storeFileInfo : storeFiles) {</span>
+<span class="source-line-no">6579</span><span id="line-6579">            try {</span>
+<span class="source-line-no">6580</span><span id="line-6580">              store.bulkLoadHFile(storeFileInfo);</span>
+<span class="source-line-no">6581</span><span id="line-6581">            } catch (FileNotFoundException ex) {</span>
+<span class="source-line-no">6582</span><span id="line-6582">              LOG.warn(getRegionInfo().getEncodedName() + " : " + storeFileInfo.toString()</span>
+<span class="source-line-no">6583</span><span id="line-6583">                + " doesn't exist any more. Skip loading the file");</span>
+<span class="source-line-no">6584</span><span id="line-6584">            }</span>
+<span class="source-line-no">6585</span><span id="line-6585">          }</span>
+<span class="source-line-no">6586</span><span id="line-6586">        }</span>
+<span class="source-line-no">6587</span><span id="line-6587">      }</span>
+<span class="source-line-no">6588</span><span id="line-6588">      if (bulkLoadEvent.getBulkloadSeqNum() &gt; 0) {</span>
+<span class="source-line-no">6589</span><span id="line-6589">        mvcc.advanceTo(bulkLoadEvent.getBulkloadSeqNum());</span>
+<span class="source-line-no">6590</span><span id="line-6590">      }</span>
+<span class="source-line-no">6591</span><span id="line-6591">    } finally {</span>
+<span class="source-line-no">6592</span><span id="line-6592">      closeBulkRegionOperation();</span>
+<span class="source-line-no">6593</span><span id="line-6593">    }</span>
+<span class="source-line-no">6594</span><span id="line-6594">  }</span>
+<span class="source-line-no">6595</span><span id="line-6595"></span>
+<span class="source-line-no">6596</span><span id="line-6596">  /**</span>
+<span class="source-line-no">6597</span><span id="line-6597">   * Replay the batch mutate for secondary replica.</span>
+<span class="source-line-no">6598</span><span id="line-6598">   * &lt;p/&gt;</span>
+<span class="source-line-no">6599</span><span id="line-6599">   * We will directly apply the cells to the memstore. This is because:</span>
+<span class="source-line-no">6600</span><span id="line-6600">   * &lt;ol&gt;</span>
+<span class="source-line-no">6601</span><span id="line-6601">   * &lt;li&gt;All the cells are gotten from {@link WALEdit}, so we only have {@link Put} and</span>
+<span class="source-line-no">6602</span><span id="line-6602">   * {@link Delete} here&lt;/li&gt;</span>
+<span class="source-line-no">6603</span><span id="line-6603">   * &lt;li&gt;The replay is single threaded, we do not need to acquire row lock, as the region is read</span>
+<span class="source-line-no">6604</span><span id="line-6604">   * only so no one else can write it.&lt;/li&gt;</span>
+<span class="source-line-no">6605</span><span id="line-6605">   * &lt;li&gt;We do not need to write WAL.&lt;/li&gt;</span>
+<span class="source-line-no">6606</span><span id="line-6606">   * &lt;li&gt;We will advance MVCC in the caller directly.&lt;/li&gt;</span>
+<span class="source-line-no">6607</span><span id="line-6607">   * &lt;/ol&gt;</span>
+<span class="source-line-no">6608</span><span id="line-6608">   */</span>
+<span class="source-line-no">6609</span><span id="line-6609">  private void replayWALBatchMutate(Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; family2Cells)</span>
+<span class="source-line-no">6610</span><span id="line-6610">    throws IOException {</span>
+<span class="source-line-no">6611</span><span id="line-6611">    startRegionOperation(Operation.REPLAY_BATCH_MUTATE);</span>
+<span class="source-line-no">6612</span><span id="line-6612">    try {</span>
+<span class="source-line-no">6613</span><span id="line-6613">      for (Map.Entry&lt;byte[], List&lt;ExtendedCell&gt;&gt; entry : family2Cells.entrySet()) {</span>
+<span class="source-line-no">6614</span><span id="line-6614">        applyToMemStore(getStore(entry.getKey()), entry.getValue(), false, memStoreSizing);</span>
+<span class="source-line-no">6615</span><span id="line-6615">      }</span>
+<span class="source-line-no">6616</span><span id="line-6616">    } finally {</span>
+<span class="source-line-no">6617</span><span id="line-6617">      closeRegionOperation(Operation.REPLAY_BATCH_MUTATE);</span>
+<span class="source-line-no">6618</span><span id="line-6618">    }</span>
+<span class="source-line-no">6619</span><span id="line-6619">  }</span>
+<span class="source-line-no">6620</span><span id="line-6620"></span>
+<span class="source-line-no">6621</span><span id="line-6621">  /**</span>
+<span class="source-line-no">6622</span><span id="line-6622">   * Replay the meta edits, i.e, flush marker, compaction marker, bulk load marker, region event</span>
+<span class="source-line-no">6623</span><span id="line-6623">   * marker, etc.</span>
+<span class="source-line-no">6624</span><span id="line-6624">   * &lt;p/&gt;</span>
+<span class="source-line-no">6625</span><span id="line-6625">   * For all events other than start flush, we will just call {@link #refreshStoreFiles()} as the</span>
+<span class="source-line-no">6626</span><span id="line-6626">   * logic is straight-forward and robust. For start flush, we need to snapshot the memstore, so</span>
+<span class="source-line-no">6627</span><span id="line-6627">   * later {@link #refreshStoreFiles()} call could drop the snapshot, otherwise we may run out of</span>
+<span class="source-line-no">6628</span><span id="line-6628">   * memory.</span>
+<span class="source-line-no">6629</span><span id="line-6629">   */</span>
+<span class="source-line-no">6630</span><span id="line-6630">  private void replayWALMetaEdit(Cell cell) throws IOException {</span>
+<span class="source-line-no">6631</span><span id="line-6631">    startRegionOperation(Operation.REPLAY_EVENT);</span>
+<span class="source-line-no">6632</span><span id="line-6632">    try {</span>
+<span class="source-line-no">6633</span><span id="line-6633">      FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(cell);</span>
+<span class="source-line-no">6634</span><span id="line-6634">      if (flushDesc != null) {</span>
+<span class="source-line-no">6635</span><span id="line-6635">        switch (flushDesc.getAction()) {</span>
+<span class="source-line-no">6636</span><span id="line-6636">          case START_FLUSH:</span>
+<span class="source-line-no">6637</span><span id="line-6637">            // for start flush, we need to take a snapshot of the current memstore</span>
+<span class="source-line-no">6638</span><span id="line-6638">            synchronized (writestate) {</span>
+<span class="source-line-no">6639</span><span id="line-6639">              if (!writestate.flushing) {</span>
+<span class="source-line-no">6640</span><span id="line-6640">                this.writestate.flushing = true;</span>
+<span class="source-line-no">6641</span><span id="line-6641">              } else {</span>
+<span class="source-line-no">6642</span><span id="line-6642">                // usually this should not happen but let's make the code more robust, it is not a</span>
+<span class="source-line-no">6643</span><span id="line-6643">                // big deal to just ignore it, the refreshStoreFiles call should have the ability to</span>
+<span class="source-line-no">6644</span><span id="line-6644">                // clean up the inconsistent state.</span>
+<span class="source-line-no">6645</span><span id="line-6645">                LOG.debug("NOT flushing {} as already flushing", getRegionInfo());</span>
+<span class="source-line-no">6646</span><span id="line-6646">                break;</span>
+<span class="source-line-no">6647</span><span id="line-6647">              }</span>
+<span class="source-line-no">6648</span><span id="line-6648">            }</span>
+<span class="source-line-no">6649</span><span id="line-6649">            MonitoredTask status =</span>
+<span class="source-line-no">6650</span><span id="line-6650">              TaskMonitor.get().createStatus("Preparing flush " + getRegionInfo());</span>
+<span class="source-line-no">6651</span><span id="line-6651">            Collection&lt;HStore&gt; storesToFlush = getStoresToFlush(flushDesc);</span>
+<span class="source-line-no">6652</span><span id="line-6652">            try {</span>
+<span class="source-line-no">6653</span><span id="line-6653">              PrepareFlushResult prepareResult =</span>
+<span class="source-line-no">6654</span><span id="line-6654">                internalPrepareFlushCache(null, flushDesc.getFlushSequenceNumber(), storesToFlush,</span>
+<span class="source-line-no">6655</span><span id="line-6655">                  status, false, FlushLifeCycleTracker.DUMMY);</span>
+<span class="source-line-no">6656</span><span id="line-6656">              if (prepareResult.result == null) {</span>
+<span class="source-line-no">6657</span><span id="line-6657">                // save the PrepareFlushResult so that we can use it later from commit flush</span>
+<span class="source-line-no">6658</span><span id="line-6658">                this.prepareFlushResult = prepareResult;</span>
+<span class="source-line-no">6659</span><span id="line-6659">                status.markComplete("Flush prepare successful");</span>
+<span class="source-line-no">6660</span><span id="line-6660">                if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">6661</span><span id="line-6661">                  LOG.debug("{} prepared flush with seqId: {}", getRegionInfo(),</span>
+<span class="source-line-no">6662</span><span id="line-6662">                    flushDesc.getFlushSequenceNumber());</span>
+<span class="source-line-no">6663</span><span id="line-6663">                }</span>
+<span class="source-line-no">6664</span><span id="line-6664">              } else {</span>
+<span class="source-line-no">6665</span><span id="line-6665">                // special case empty memstore. We will still save the flush result in this case,</span>
+<span class="source-line-no">6666</span><span id="line-6666">                // since our memstore is empty, but the primary is still flushing</span>
+<span class="source-line-no">6667</span><span id="line-6667">                if (</span>
+<span class="source-line-no">6668</span><span id="line-6668">                  prepareResult.getResult().getResult()</span>
+<span class="source-line-no">6669</span><span id="line-6669">                      == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY</span>
+<span class="source-line-no">6670</span><span id="line-6670">                ) {</span>
+<span class="source-line-no">6671</span><span id="line-6671">                  this.prepareFlushResult = prepareResult;</span>
+<span class="source-line-no">6672</span><span id="line-6672">                  if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">6673</span><span id="line-6673">                    LOG.debug("{} prepared empty flush with seqId: {}", getRegionInfo(),</span>
+<span class="source-line-no">6674</span><span id="line-6674">                      flushDesc.getFlushSequenceNumber());</span>
+<span class="source-line-no">6675</span><span id="line-6675">                  }</span>
+<span class="source-line-no">6676</span><span id="line-6676">                }</span>
+<span class="source-line-no">6677</span><span id="line-6677">                status.abort("Flush prepare failed with " + prepareResult.result);</span>
+<span class="source-line-no">6678</span><span id="line-6678">                // nothing much to do. prepare flush failed because of some reason.</span>
+<span class="source-line-no">6679</span><span id="line-6679">              }</span>
+<span class="source-line-no">6680</span><span id="line-6680">            } finally {</span>
+<span class="source-line-no">6681</span><span id="line-6681">              status.cleanup();</span>
+<span class="source-line-no">6682</span><span id="line-6682">            }</span>
+<span class="source-line-no">6683</span><span id="line-6683">            break;</span>
+<span class="source-line-no">6684</span><span id="line-6684">          case ABORT_FLUSH:</span>
+<span class="source-line-no">6685</span><span id="line-6685">            // do nothing, an abort flush means the source region server will crash itself, after</span>
+<span class="source-line-no">6686</span><span id="line-6686">            // the primary region online, it will send us an open region marker, then we can clean</span>
+<span class="source-line-no">6687</span><span id="line-6687">            // up the memstore.</span>
+<span class="source-line-no">6688</span><span id="line-6688">            synchronized (writestate) {</span>
+<span class="source-line-no">6689</span><span id="line-6689">              writestate.flushing = false;</span>
+<span class="source-line-no">6690</span><span id="line-6690">            }</span>
+<span class="source-line-no">6691</span><span id="line-6691">            break;</span>
+<span class="source-line-no">6692</span><span id="line-6692">          case COMMIT_FLUSH:</span>
+<span class="source-line-no">6693</span><span id="line-6693">          case CANNOT_FLUSH:</span>
+<span class="source-line-no">6694</span><span id="line-6694">            // just call refreshStoreFiles</span>
+<span class="source-line-no">6695</span><span id="line-6695">            refreshStoreFiles();</span>
+<span class="source-line-no">6696</span><span id="line-6696">            logRegionFiles();</span>
+<span class="source-line-no">6697</span><span id="line-6697">            synchronized (writestate) {</span>
+<span class="source-line-no">6698</span><span id="line-6698">              writestate.flushing = false;</span>
+<span class="source-line-no">6699</span><span id="line-6699">            }</span>
+<span class="source-line-no">6700</span><span id="line-6700">            break;</span>
+<span class="source-line-no">6701</span><span id="line-6701">          default:</span>
+<span class="source-line-no">6702</span><span id="line-6702">            LOG.warn("{} received a flush event with unknown action: {}", getRegionInfo(),</span>
+<span class="source-line-no">6703</span><span id="line-6703">              TextFormat.shortDebugString(flushDesc));</span>
+<span class="source-line-no">6704</span><span id="line-6704">        }</span>
+<span class="source-line-no">6705</span><span id="line-6705">      } else {</span>
+<span class="source-line-no">6706</span><span id="line-6706">        // for all other region events, we will do a refreshStoreFiles</span>
+<span class="source-line-no">6707</span><span id="line-6707">        refreshStoreFiles();</span>
+<span class="source-line-no">6708</span><span id="line-6708">        logRegionFiles();</span>
+<span class="source-line-no">6709</span><span id="line-6709">      }</span>
+<span class="source-line-no">6710</span><span id="line-6710">    } finally {</span>
+<span class="source-line-no">6711</span><span id="line-6711">      closeRegionOperation(Operation.REPLAY_EVENT);</span>
+<span class="source-line-no">6712</span><span id="line-6712">    }</span>
+<span class="source-line-no">6713</span><span id="line-6713">  }</span>
+<span class="source-line-no">6714</span><span id="line-6714"></span>
+<span class="source-line-no">6715</span><span id="line-6715">  /**</span>
+<span class="source-line-no">6716</span><span id="line-6716">   * Replay remote wal entry sent by primary replica.</span>
+<span class="source-line-no">6717</span><span id="line-6717">   * &lt;p/&gt;</span>
+<span class="source-line-no">6718</span><span id="line-6718">   * Should only call this method on secondary replicas.</span>
+<span class="source-line-no">6719</span><span id="line-6719">   */</span>
+<span class="source-line-no">6720</span><span id="line-6720">  void replayWALEntry(WALEntry entry, CellScanner cells) throws IOException {</span>
+<span class="source-line-no">6721</span><span id="line-6721">    long timeout = -1L;</span>
+<span class="source-line-no">6722</span><span id="line-6722">    Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();</span>
+<span class="source-line-no">6723</span><span id="line-6723">    if (call.isPresent()) {</span>
+<span class="source-line-no">6724</span><span id="line-6724">      long deadline = call.get().getDeadline();</span>
+<span class="source-line-no">6725</span><span id="line-6725">      if (deadline &lt; Long.MAX_VALUE) {</span>
+<span class="source-line-no">6726</span><span id="line-6726">        timeout = deadline - EnvironmentEdgeManager.currentTime();</span>
+<span class="source-line-no">6727</span><span id="line-6727">        if (timeout &lt;= 0) {</span>
+<span class="source-line-no">6728</span><span id="line-6728">          throw new TimeoutIOException("Timeout while replaying edits for " + getRegionInfo());</span>
+<span class="source-line-no">6729</span><span id="line-6729">        }</span>
+<span class="source-line-no">6730</span><span id="line-6730">      }</span>
+<span class="source-line-no">6731</span><span id="line-6731">    }</span>
+<span class="source-line-no">6732</span><span id="line-6732">    if (timeout &gt; 0) {</span>
+<span class="source-line-no">6733</span><span id="line-6733">      try {</span>
+<span class="source-line-no">6734</span><span id="line-6734">        if (!replayLock.tryLock(timeout, TimeUnit.MILLISECONDS)) {</span>
+<span class="source-line-no">6735</span><span id="line-6735">          throw new TimeoutIOException(</span>
+<span class="source-line-no">6736</span><span id="line-6736">            "Timeout while waiting for lock when replaying edits for " + getRegionInfo());</span>
+<span class="source-line-no">6737</span><span id="line-6737">        }</span>
+<span class="source-line-no">6738</span><span id="line-6738">      } catch (InterruptedException e) {</span>
+<span class="source-line-no">6739</span><span id="line-6739">        throw throwOnInterrupt(e);</span>
+<span class="source-line-no">6740</span><span id="line-6740">      }</span>
+<span class="source-line-no">6741</span><span id="line-6741">    } else {</span>
+<span class="source-line-no">6742</span><span id="line-6742">      replayLock.lock();</span>
+<span class="source-line-no">6743</span><span id="line-6743">    }</span>
+<span class="source-line-no">6744</span><span id="line-6744">    try {</span>
+<span class="source-line-no">6745</span><span id="line-6745">      int count = entry.getAssociatedCellCount();</span>
+<span class="source-line-no">6746</span><span id="line-6746">      long sequenceId = entry.getKey().getLogSequenceNumber();</span>
+<span class="source-line-no">6747</span><span id="line-6747">      if (lastReplayedSequenceId &gt;= sequenceId) {</span>
+<span class="source-line-no">6748</span><span id="line-6748">        // we have already replayed this edit, skip</span>
+<span class="source-line-no">6749</span><span id="line-6749">        // remember to advance the CellScanner, as we may have multiple WALEntries, we may still</span>
+<span class="source-line-no">6750</span><span id="line-6750">        // need apply later WALEntries</span>
+<span class="source-line-no">6751</span><span id="line-6751">        for (int i = 0; i &lt; count; i++) {</span>
+<span class="source-line-no">6752</span><span id="line-6752">          // Throw index out of bounds if our cell count is off</span>
+<span class="source-line-no">6753</span><span id="line-6753">          if (!cells.advance()) {</span>
+<span class="source-line-no">6754</span><span id="line-6754">            throw new ArrayIndexOutOfBoundsException("Expected=" + count + ", index=" + i);</span>
+<span class="source-line-no">6755</span><span id="line-6755">          }</span>
+<span class="source-line-no">6756</span><span id="line-6756">        }</span>
+<span class="source-line-no">6757</span><span id="line-6757">        return;</span>
+<span class="source-line-no">6758</span><span id="line-6758">      }</span>
+<span class="source-line-no">6759</span><span id="line-6759">      Map&lt;byte[], List&lt;ExtendedCell&gt;&gt; family2Cells = new TreeMap&lt;&gt;(Bytes.BYTES_COMPARATOR);</span>
+<span class="source-line-no">6760</span><span id="line-6760">      for (int i = 0; i &lt; count; i++) {</span>
+<span class="source-line-no">6761</span><span id="line-6761">        // Throw index out of bounds if our cell count is off</span>
+<span class="source-line-no">6762</span><span id="line-6762">        if (!cells.advance()) {</span>
+<span class="source-line-no">6763</span><span id="line-6763">          throw new ArrayIndexOutOfBoundsException("Expected=" + count + ", index=" + i);</span>
+<span class="source-line-no">6764</span><span id="line-6764">        }</span>
+<span class="source-line-no">6765</span><span id="line-6765">        Cell c = cells.current();</span>
+<span class="source-line-no">6766</span><span id="line-6766">        assert c instanceof ExtendedCell;</span>
+<span class="source-line-no">6767</span><span id="line-6767">        ExtendedCell cell = (ExtendedCell) c;</span>
+<span class="source-line-no">6768</span><span id="line-6768">        if (WALEdit.isMetaEditFamily(cell)) {</span>
+<span class="source-line-no">6769</span><span id="line-6769">          // If there is meta edit, i.e, we have done flush/compaction/open, then we need to apply</span>
+<span class="source-line-no">6770</span><span id="line-6770">          // the previous cells first, and then replay the special meta edit. The meta edit is like</span>
+<span class="source-line-no">6771</span><span id="line-6771">          // a barrier, We need to keep the order. For example, the flush marker will contain a</span>
+<span class="source-line-no">6772</span><span id="line-6772">          // flush sequence number, which makes us possible to drop memstore content, but if we</span>
+<span class="source-line-no">6773</span><span id="line-6773">          // apply some edits which have greater sequence id first, then we can not drop the</span>
+<span class="source-line-no">6774</span><span id="line-6774">          // memstore content when replaying the flush marker, which is not good as we could run out</span>
+<span class="source-line-no">6775</span><span id="line-6775">          // of memory.</span>
+<span class="source-line-no">6776</span><span id="line-6776">          // And usually, a meta edit will have a special WALEntry for it, so this is just a safe</span>
+<span class="source-line-no">6777</span><span id="line-6777">          // guard logic to make sure we do not break things in the worst case.</span>
+<span class="source-line-no">6778</span><span id="line-6778">          if (!family2Cells.isEmpty()) {</span>
+<span class="source-line-no">6779</span><span id="line-6779">            replayWALBatchMutate(family2Cells);</span>
+<span class="source-line-no">6780</span><span id="line-6780">            family2Cells.clear();</span>
+<span class="source-line-no">6781</span><span id="line-6781">          }</span>
+<span class="source-line-no">6782</span><span id="line-6782">          replayWALMetaEdit(cell);</span>
+<span class="source-line-no">6783</span><span id="line-6783">        } else {</span>
+<span class="source-line-no">6784</span><span id="line-6784">          family2Cells.computeIfAbsent(CellUtil.cloneFamily(cell), k -&gt; new ArrayList&lt;&gt;())</span>
+<span class="source-line-no">6785</span><span id="line-6785">            .add(cell);</span>
+<span class="source-line-no">6786</span><span id="line-6786">        }</span>
+<span class="source-line-no">6787</span><span id="line-6787">      }</span>
+<span class="source-line-no">6788</span><span id="line-6788">      // do not forget to apply the remaining cells</span>
+<span class="source-line-no">6789</span><span id="line-6789">      if (!family2Cells.isEmpty()) {</span>
+<span class="source-line-no">6790</span><span id="line-6790">        replayWALBatchMutate(family2Cells);</span>
+<span class="source-line-no">6791</span><span id="line-6791">      }</span>
+<span class="source-line-no">6792</span><span id="line-6792">      mvcc.advanceTo(sequenceId);</span>
+<span class="source-line-no">6793</span><span id="line-6793">      lastReplayedSequenceId = sequenceId;</span>
+<span class="source-line-no">6794</span><span id="line-6794">    } finally {</span>
+<span class="source-line-no">6795</span><span id="line-6795">      replayLock.unlock();</span>
+<span class="source-line-no">6796</span><span id="line-6796">    }</span>
+<span class="source-line-no">6797</span><span id="line-6797">  }</span>
+<span class="source-line-no">6798</span><span id="line-6798"></span>
+<span class="source-line-no">6799</span><span id="line-6799">  /**</span>
+<span class="source-line-no">6800</span><span id="line-6800">   * If all stores ended up dropping their snapshots, we can safely drop the prepareFlushResult</span>
+<span class="source-line-no">6801</span><span id="line-6801">   */</span>
+<span class="source-line-no">6802</span><span id="line-6802">  private void dropPrepareFlushIfPossible() {</span>
+<span class="source-line-no">6803</span><span id="line-6803">    if (writestate.flushing) {</span>
+<span class="source-line-no">6804</span><span id="line-6804">      boolean canDrop = true;</span>
+<span class="source-line-no">6805</span><span id="line-6805">      if (prepareFlushResult.storeFlushCtxs != null) {</span>
+<span class="source-line-no">6806</span><span id="line-6806">        for (Entry&lt;byte[], StoreFlushContext&gt; entry : prepareFlushResult.storeFlushCtxs</span>
+<span class="source-line-no">6807</span><span id="line-6807">          .entrySet()) {</span>
+<span class="source-line-no">6808</span><span id="line-6808">          HStore store = getStore(entry.getKey());</span>
+<span class="source-line-no">6809</span><span id="line-6809">          if (store == null) {</span>
+<span class="source-line-no">6810</span><span id="line-6810">            continue;</span>
+<span class="source-line-no">6811</span><span id="line-6811">          }</span>
+<span class="source-line-no">6812</span><span id="line-6812">          if (store.getSnapshotSize().getDataSize() &gt; 0) {</span>
+<span class="source-line-no">6813</span><span id="line-6813">            canDrop = false;</span>
+<span class="source-line-no">6814</span><span id="line-6814">            break;</span>
+<span class="source-line-no">6815</span><span id="line-6815">          }</span>
+<span class="source-line-no">6816</span><span id="line-6816">        }</span>
+<span class="source-line-no">6817</span><span id="line-6817">      }</span>
+<span class="source-line-no">6818</span><span id="line-6818"></span>
+<span class="source-line-no">6819</span><span id="line-6819">      // this means that all the stores in the region has finished flushing, but the WAL marker</span>
+<span class="source-line-no">6820</span><span id="line-6820">      // may not have been written or we did not receive it yet.</span>
+<span class="source-line-no">6821</span><span id="line-6821">      if (canDrop) {</span>
+<span class="source-line-no">6822</span><span id="line-6822">        writestate.flushing = false;</span>
+<span class="source-line-no">6823</span><span id="line-6823">        this.prepareFlushResult = null;</span>
+<span class="source-line-no">6824</span><span id="line-6824">      }</span>
+<span class="source-line-no">6825</span><span id="line-6825">    }</span>
+<span class="source-line-no">6826</span><span id="line-6826">  }</span>
+<span class="source-line-no">6827</span><span id="line-6827"></span>
+<span class="source-line-no">6828</span><span id="line-6828">  @Override</span>
+<span class="source-line-no">6829</span><span id="line-6829">  public boolean refreshStoreFiles() throws IOException {</span>
+<span class="source-line-no">6830</span><span id="line-6830">    return refreshStoreFiles(false);</span>
+<span class="source-line-no">6831</span><span id="line-6831">  }</span>
+<span class="source-line-no">6832</span><span id="line-6832"></span>
+<span class="source-line-no">6833</span><span id="line-6833">  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "NN_NAKED_NOTIFY",</span>
+<span class="source-line-no">6834</span><span id="line-6834">      justification = "Notify is about post replay. Intentional")</span>
+<span class="source-line-no">6835</span><span id="line-6835">  protected boolean refreshStoreFiles(boolean force) throws IOException {</span>
+<span class="source-line-no">6836</span><span id="line-6836">    if (!force &amp;&amp; ServerRegionReplicaUtil.isDefaultReplica(this.getRegionInfo())) {</span>
+<span class="source-line-no">6837</span><span id="line-6837">      return false; // if primary nothing to do</span>
+<span class="source-line-no">6838</span><span id="line-6838">    }</span>
+<span class="source-line-no">6839</span><span id="line-6839"></span>
+<span class="source-line-no">6840</span><span id="line-6840">    if (LOG.isDebugEnabled()) {</span>
+<span class="source-line-no">6841</span><span id="line-6841">      LOG.debug(getRegionInfo().getEncodedName() + " : "</span>
+<span class="source-line-no">6842</span><span id="line-6842">        + "Refreshing store files to see whether we can free up memstore");</span>
+<span class="source-line-no">6843</span><span id="line-6843">    }</span>
+<span class="source-line-no">6844</span><span id="line-6844"></span>
+<span class="source-line-no">6845</span><span id="line-6845">    long totalFreedDataSize = 0;</span>
+<span class="source-line-no">6846</span><span id="line-6846"></span>
+<span class="source-line-no">6847</span><span id="line-6847">    long smallestSeqIdInStores = Long.MAX_VALUE;</span>
+<span class="source-line-no">6848</span><span id="line-6848"></span>
+<span class="source-line-no">6849</span><span id="line-6849">    startRegionOperation(); // obtain region close lock</span>
+<span class="source-line-no">6850</span><span id="line-6850">    try {</span>
+<span class="source-line-no">6851</span><span id="line-6851">      Map&lt;HStore, Long&gt; map = new HashMap&lt;&gt;();</span>
+<span class="source-line-no">6852</span><span id="line-6852">      synchronized (writestate) {</span>
+<span class="source-line-no">6853</span><span id="line-6853">        for (HStore store : stores.values()) {</span>
+<span class="source-line-no">6854</span><span id="line-6854">          // TODO: some stores might see new data from flush, while others do not which</span>
+<span class="source-line-no">6855</span><span id="line-6855">          // MIGHT break atomic edits across column families.</span>
+<span class="source-line-no">6856</span><span id="line-6856">          long maxSeqIdBefore = store.getMaxSequenceId().orElse(0L);</span>
+<span class="source-line-no">6857</span><span id="line-6857"></span>
+<span class="source-line-no">6858</span><span id="line-6858">          // refresh the store files. This is similar to observing a region open wal marker.</span>
+<span class="source-line-no">6859</span><span id="line-6859">          store.refreshStoreFiles();</span>
+<span class="source-line-no">6860</span><span id="line-6860"></span>
+<span class="source-line-no">6861</span><span id="line-6861">          long storeSeqId = store.getMaxSequenceId().orElse(0L);</span>
+<span class="source-line-no">6862</span><span id="line-6862">          if (storeSeqId &lt; smallestSeqIdInStores) {</span>
+<span class="source-line-no">6863</span><span id="line-6863">            smallestSeqIdInStores = storeSeqId;</span>
+<span class="source-line-no">6864</span><span id="line-6864">          }</span>
+<span class="source-line-no">6865</span><span id="line-6865"></span>
+<span class="source-line-no">6866</span><span id="line-6866">          // see whether we can drop the memstore or the snapshot</span>
+<span class="source-line-no">6867</span><span id="line-6867">          if (storeSeqId &gt; maxSeqIdBefore) {</span>
+<span class="source-line-no">6868</span><span id="line-6868">            if (writestate.flushing) {</span>
+<span class="source-line-no">6869</span><span id="line-6869">              // only drop memstore snapshots if they are smaller than last flush for the store</span>
+<span class="source-line-no">6870</span><span id="line-6870">              if (this.prepareFlushResult.flushOpSeqId &lt;= storeSeqId) {</span>
+<span class="source-line-no">6871</span><span id="line-6871">                StoreFlushContext ctx = this.prepareFlushResult.storeFlushCtxs == null</span>
+<span class="source-line-no">6872</span><span id="line-6872">                  ? null</span>
+<span class="source-line-no">6873</span><span id="line-6873">                  : this.prepareFlushResult.storeFlushCtxs</span>
+<span class="source-line-no">6874</span><span id="line-6874">                    .get(store.getColumnFamilyDescriptor().getName());</span>
+<span class="source-line-no">6875</span><span id="line-6875">                if (ctx != null) {</span>
+<span class="source-line-no">6876</span><span id="line-6876">                  MemStoreSize mss = store.getFlushableSize();</span>
+<span class="source-line-no">6877</span><span id="line-6877">                  ctx.abort();</span>
+<span class="source-line-no">6878</span><span id="line-6878">                  this.decrMemStoreSize(mss);</span>
+<span class="source-line-no">6879</span><span id="line-6879">                  this.prepareFlushResult.storeFlushCtxs</span>
+<span class="source-line-no">6880</span><span id="line-6880">                    .remove(store.getColumnFamilyDescriptor().getName());</span>
+<span class="source-line-no">6881</span><span id="line-6881">                  totalFreedDataSize += mss.getDataSize();</span>
+<span class="source-line-no">6882</span><span id="line-6882">                }</span>
+<span class="source-line-no">6883</span><span id="line-6883">              }</span>
+<span class="source-line-no">6884</span><span id="line-6884">            }</span>
+<span class="source-line-no">6885</span><span id="line-6885"></span>
+<span class="source-line-no">6886</span><span id="line-6886">            map.put(store, storeSeqId);</span>
+<span class="source-line-no">6887</span><span id="line-6887">          }</span>
+<span class="source-line-no">6888</span><span id="line-6888">        }</span>
+<span class="source-line-no">6889</span><span id="line-6889"></span>
+<span class="source-line-no">6890</span><span id="line-6890">        // if all stores ended up dropping their snapshots, we can safely drop the</span>
+<span class="source-line-no">6891</span><span id="line-6891">        // prepareFlushResult</span>
+<span class="source-line-no">6892</span><span id="line-6892">        dropPrepareFlushIfPossible();</span>
 <span class="source-line-no">6893</span><span id="line-6893"></span>
-<span class="source-line-no">6894</span><span id="line-6894">  /**</span>
-<span class="source-line-no">6895</span><span id="line-6895">   * Used by tests</span>
-<span class="source-line-no">6896</span><span id="line-6896">   * @param s    Store to add edit too.</span>
-<span class="source-line-no">6897</span><span id="line-6897">   * @param cell Cell to add.</span>
-<span class="source-line-no">6898</span><span id="line-6898">   */</span>
-<span class="source-line-no">6899</span><span id="line-6899">  protected void restoreEdit(HStore s, ExtendedCell cell, MemStoreSizing memstoreAccounting) {</span>
-<span class="source-line-no">6900</span><span id="line-6900">    s.add(cell, memstoreAccounting);</span>
-<span class="source-line-no">6901</span><span id="line-6901">  }</span>
-<span class="source-line-no">6902</span><span id="line-6902"></span>
-<span class="source-line-no">6903</span><span id="line-6903">  /**</span>
-<span class="source-line-no">6904</span><span id="line-6904">   * make sure have been through lease recovery before get file status, so the file length can be</span>
-<span class="source-line-no">6905</span><span id="line-6905">   * trusted.</span>
-<span class="source-line-no">6906</span><span id="line-6906">   * @param p File to check.</span>
-<span class="source-line-no">6907</span><span id="line-6907">   * @return True if file was zero-length (and if so, we'll delete it in here).</span>
-<span class="source-line-no">6908</span><span id="line-6908">   */</span>
-<span class="source-line-no">6909</span><span id="line-6909">  private static boolean isZeroLengthThenDelete(final FileSystem fs, final FileStatus stat,</span>
-<span class="source-line-no">6910</span><span id="line-6910">    final Path p) throws IOException {</span>
-<span class="source-line-no">6911</span><span id="line-6911">    if (stat.getLen() &gt; 0) {</span>
-<span class="source-line-no">6912</span><span id="line-6912">      return false;</span>
-<span class="source-line-no">6913</span><span id="line-6913">    }</span>
-<span class="source-line-no">6914</span><span id="line-6914">    LOG.warn("File " + p + " is zero-length, deleting.");</span>
-<span class="source-line-no">6915</span><span id="line-6915">    fs.delete(p, false);</span>
-<span class="source-line-no">6916</span><span id="line-6916">    return true;</span>
-<span class="source-line-no">6917</span><span id="line-6917">  }</span>
-<span class="source-line-no">6918</span><span id="line-6918"></span>
-<span class="source-line-no">6919</span><span id="line-6919">  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)</span>
-<span class="source-line-no">6920</span><span id="line-6920">    throws IOException {</span>
-<span class="source-line-no">6921</span><span id="line-6921">    if (family.isMobEnabled()) {</span>
-<span class="source-line-no">6922</span><span id="line-6922">      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {</span>
-<span class="source-line-no">6923</span><span id="line-6923">        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS</span>
-<span class="source-line-no">6924</span><span id="line-6924">          + " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY</span>
-<span class="source-line-no">6925</span><span id="line-6925">          + " accordingly.");</span>
-<span class="source-line-no">6926</span><span id="line-6926">      }</span>
-<span class="source-line-no">6927</span><span id="line-6927">      return new HMobStore(this, family, this.conf, warmup);</span>
-<span class="source-line-no">6928</span><span id="line-6928">    }</span>
-<span class="source-line-no">6929</span><span id="line-6929">    return new HStore(this, family, this.conf, warmup);</span>
-<span class="source-line-no">6930</span><span id="line-6930">  }</span>
-<span class="source-line-no">6931</span><span id="line-6931"></span>
-<span class="source-line-no">6932</span><span id="line-6932">  @Override</span>
-<span class="source-line-no">6933</span><span id="line-6933">  public HStore getStore(byte[] column) {</span>
-<span class="source-line-no">6934</span><span id="line-6934">    return this.stores.get(column);</span>
-<span class="source-line-no">6935</span><span id="line-6935">  }</span>
-<span class="source-line-no">6936</span><span id="line-6936"></span>
-<span class="source-line-no">6937</span><span id="line-6937">  /**</span>
-<span class="source-line-no">6938</span><span id="line-6938">   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on</span>
-<span class="source-line-no">6939</span><span id="line-6939">   * the list.</span>
-<span class="source-line-no">6940</span><span id="line-6940">   */</span>
-<span class="source-line-no">6941</span><span id="line-6941">  private HStore getStore(Cell cell) {</span>
-<span class="source-line-no">6942</span><span id="line-6942">    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))</span>
-<span class="source-line-no">6943</span><span id="line-6943">      .map(e -&gt; e.getValue()).findFirst().orElse(null);</span>
-<span class="source-line-no">6944</span><span id="line-6944">  }</span>
-<span class="source-line-no">6945</span><span id="line-6945"></span>
-<span class="source-line-no">6946</span><span id="line-6946">  @Override</span>
-<span class="source-line-no">6947</span><span id="line-6947">  public List&lt;HStore&gt; getStores() {</span>
-<span class="source-line-no">6948</span><span id="line-6948">    return new ArrayList&lt;&gt;(stores.values());</span>
-<span class="source-line-no">6949</span><span id="line-6949">  }</span>
-<span class="source-line-no">6950</span><span id="line-6950"></span>
-<span class="source-line-no">6951</span><span id="line-6951">  @Override</span>
-<span class="source-line-no">6952</span><span id="line-6952">  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {</span>
-<span class="source-line-no">6953</span><span id="line-6953">    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();</span>
-<span class="source-line-no">6954</span><span id="line-6954">    synchronized (closeLock) {</span>
-<span class="source-line-no">6955</span><span id="line-6955">      for (byte[] column : columns) {</span>
-<span class="source-line-no">6956</span><span id="line-6956">        HStore store = this.stores.get(column);</span>
-<span class="source-line-no">6957</span><span id="line-6957">        if (store == null) {</span>
-<span class="source-line-no">6958</span><span id="line-6958">          throw new IllegalArgumentException(</span>
-<span class="source-line-no">6959</span><span id="line-6959">            "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");</span>
-<span class="source-line-no">6960</span><span id="line-6960">        }</span>
-<span class="source-line-no">6961</span><span id="line-6961">        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();</span>
-<span class="source-line-no">6962</span><span id="line-6962">        if (storeFiles == null) {</span>
-<span class="source-line-no">6963</span><span id="line-6963">          continue;</span>
-<span class="source-line-no">6964</span><span id="line-6964">        }</span>
-<span class="source-line-no">6965</span><span id="line-6965">        for (HStoreFile storeFile : storeFiles) {</span>
-<span class="source-line-no">6966</span><span id="line-6966">          storeFileNames.add(storeFile.getPath().toString());</span>
-<span class="source-line-no">6967</span><span id="line-6967">        }</span>
-<span class="source-line-no">6968</span><span id="line-6968"></span>
-<span class="source-line-no">6969</span><span id="line-6969">        logRegionFiles();</span>
-<span class="source-line-no">6970</span><span id="line-6970">      }</span>
-<span class="source-line-no">6971</span><span id="line-6971">    }</span>
-<span class="source-line-no">6972</span><span id="line-6972">    return storeFileNames;</span>
-<span class="source-line-no">6973</span><span id="line-6973">  }</span>
-<span class="source-line-no">6974</span><span id="line-6974"></span>
-<span class="source-line-no">6975</span><span id="line-6975">  //////////////////////////////////////////////////////////////////////////////</span>
-<span class="source-line-no">6976</span><span id="line-6976">  // Support code</span>
-<span class="source-line-no">6977</span><span id="line-6977">  //////////////////////////////////////////////////////////////////////////////</span>
-<span class="source-line-no">6978</span><span id="line-6978"></span>
-<span class="source-line-no">6979</span><span id="line-6979">  /** Make sure this is a valid row for the HRegion */</span>
-<span class="source-line-no">6980</span><span id="line-6980">  void checkRow(byte[] row, String op) throws IOException {</span>
-<span class="source-line-no">6981</span><span id="line-6981">    if (!rowIsInRange(getRegionInfo(), row)) {</span>
-<span class="source-line-no">6982</span><span id="line-6982">      throw new WrongRegionException("Requested row out of range for " + op + " on HRegion " + this</span>
-<span class="source-line-no">6983</span><span id="line-6983">        + ", startKey='" + Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='"</span>
-<span class="source-line-no">6984</span><span id="line-6984">        + Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" + Bytes.toStringBinary(row)</span>
-<span class="source-line-no">6985</span><span id="line-6985">        + "'");</span>
-<span class="source-line-no">6986</span><span id="line-6986">    }</span>
-<span class="source-line-no">6987</span><span id="line-6987">  }</span>
-<span class="source-line-no">6988</span><span id="line-6988"></span>
-<span class="source-line-no">6989</span><span id="line-6989">  /**</span>
-<span class="source-line-no">6990</span><span id="line-6990">   * Get an exclusive ( write lock ) lock on a given row.</span>
-<span class="source-line-no">6991</span><span id="line-6991">   * @param row Which row to lock.</span>
-<span class="source-line-no">6992</span><span id="line-6992">   * @return A locked RowLock. The lock is exclusive and already aqquired.</span>
-<span class="source-line-no">6993</span><span id="line-6993">   */</span>
-<span class="source-line-no">6994</span><span id="line-6994">  public RowLock getRowLock(byte[] row) throws IOException {</span>
-<span class="source-line-no">6995</span><span id="line-6995">    return getRowLock(row, false);</span>
-<span class="source-line-no">6996</span><span id="line-6996">  }</span>
-<span class="source-line-no">6997</span><span id="line-6997"></span>
-<span class="source-line-no">6998</span><span id="line-6998">  @Override</span>
-<span class="source-line-no">6999</span><span id="line-6999">  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {</span>
-<span class="source-line-no">7000</span><span id="line-7000">    checkRow(row, "row lock");</span>
-<span class="source-line-no">7001</span><span id="line-7001">    return getRowLock(row, readLock, null);</span>
-<span class="source-line-no">7002</span><span id="line-7002">  }</span>
-<span class="source-line-no">7003</span><span id="line-7003"></span>
-<span class="source-line-no">7004</span><span id="line-7004">  Span createRegionSpan(String name) {</span>
-<span class="source-line-no">7005</span><span id="line-7005">    return TraceUtil.createSpan(name).setAttribute(REGION_NAMES_KEY,</span>
-<span class="source-line-no">7006</span><span id="line-7006">      Collections.singletonList(getRegionInfo().getRegionNameAsString()));</span>
+<span class="source-line-no">6894</span><span id="line-6894">        // advance the mvcc read point so that the new flushed files are visible.</span>
+<span class="source-line-no">6895</span><span id="line-6895">        // either greater than flush seq number or they were already picked up via flush.</span>
+<span class="source-line-no">6896</span><span id="line-6896">        for (HStore s : stores.values()) {</span>
+<span class="source-line-no">6897</span><span id="line-6897">          mvcc.advanceTo(s.getMaxMemStoreTS().orElse(0L));</span>
+<span class="source-line-no">6898</span><span id="line-6898">        }</span>
+<span class="source-line-no">6899</span><span id="line-6899"></span>
+<span class="source-line-no">6900</span><span id="line-6900">        // smallestSeqIdInStores is the seqId that we have a corresponding hfile for. We can safely</span>
+<span class="source-line-no">6901</span><span id="line-6901">        // skip all edits that are to be replayed in the future with that has a smaller seqId</span>
+<span class="source-line-no">6902</span><span id="line-6902">        // than this. We are updating lastReplayedOpenRegionSeqId so that we can skip all edits</span>
+<span class="source-line-no">6903</span><span id="line-6903">        // that we have picked the flush files for</span>
+<span class="source-line-no">6904</span><span id="line-6904">        if (this.lastReplayedOpenRegionSeqId &lt; smallestSeqIdInStores) {</span>
+<span class="source-line-no">6905</span><span id="line-6905">          this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;</span>
+<span class="source-line-no">6906</span><span id="line-6906">        }</span>
+<span class="source-line-no">6907</span><span id="line-6907">      }</span>
+<span class="source-line-no">6908</span><span id="line-6908">      if (!map.isEmpty()) {</span>
+<span class="source-line-no">6909</span><span id="line-6909">        for (Map.Entry&lt;HStore, Long&gt; entry : map.entrySet()) {</span>
+<span class="source-line-no">6910</span><span id="line-6910">          // Drop the memstore contents if they are now smaller than the latest seen flushed file</span>
+<span class="source-line-no">6911</span><span id="line-6911">          totalFreedDataSize +=</span>
+<span class="source-line-no">6912</span><span id="line-6912">            dropMemStoreContentsForSeqId(entry.getValue(), entry.getKey()).getDataSize();</span>
+<span class="source-line-no">6913</span><span id="line-6913">        }</span>
+<span class="source-line-no">6914</span><span id="line-6914">      }</span>
+<span class="source-line-no">6915</span><span id="line-6915">      // C. Finally notify anyone waiting on memstore to clear:</span>
+<span class="source-line-no">6916</span><span id="line-6916">      // e.g. checkResources().</span>
+<span class="source-line-no">6917</span><span id="line-6917">      synchronized (this) {</span>
+<span class="source-line-no">6918</span><span id="line-6918">        notifyAll(); // FindBugs NN_NAKED_NOTIFY</span>
+<span class="source-line-no">6919</span><span id="line-6919">      }</span>
+<span class="source-line-no">6920</span><span id="line-6920">      return totalFreedDataSize &gt; 0;</span>
+<span class="source-line-no">6921</span><span id="line-6921">    } finally {</span>
+<span class="source-line-no">6922</span><span id="line-6922">      closeRegionOperation();</span>
+<span class="source-line-no">6923</span><span id="line-6923">    }</span>
+<span class="source-line-no">6924</span><span id="line-6924">  }</span>
+<span class="source-line-no">6925</span><span id="line-6925"></span>
+<span class="source-line-no">6926</span><span id="line-6926">  private void logRegionFiles() {</span>
+<span class="source-line-no">6927</span><span id="line-6927">    if (LOG.isTraceEnabled()) {</span>
+<span class="source-line-no">6928</span><span id="line-6928">      LOG.trace(getRegionInfo().getEncodedName() + " : Store files for region: ");</span>
+<span class="source-line-no">6929</span><span id="line-6929">      stores.values().stream().filter(s -&gt; s.getStorefiles() != null)</span>
+<span class="source-line-no">6930</span><span id="line-6930">        .flatMap(s -&gt; s.getStorefiles().stream())</span>
+<span class="source-line-no">6931</span><span id="line-6931">        .forEachOrdered(sf -&gt; LOG.trace(getRegionInfo().getEncodedName() + " : " + sf));</span>
+<span class="source-line-no">6932</span><span id="line-6932">    }</span>
+<span class="source-line-no">6933</span><span id="line-6933">  }</span>
+<span class="source-line-no">6934</span><span id="line-6934"></span>
+<span class="source-line-no">6935</span><span id="line-6935">  /**</span>
+<span class="source-line-no">6936</span><span id="line-6936">   * Checks whether the given regionName is either equal to our region, or that the regionName is</span>
+<span class="source-line-no">6937</span><span id="line-6937">   * the primary region to our corresponding range for the secondary replica.</span>
+<span class="source-line-no">6938</span><span id="line-6938">   */</span>
+<span class="source-line-no">6939</span><span id="line-6939">  private void checkTargetRegion(byte[] encodedRegionName, String exceptionMsg, Object payload)</span>
+<span class="source-line-no">6940</span><span id="line-6940">    throws WrongRegionException {</span>
+<span class="source-line-no">6941</span><span id="line-6941">    if (Bytes.equals(this.getRegionInfo().getEncodedNameAsBytes(), encodedRegionName)) {</span>
+<span class="source-line-no">6942</span><span id="line-6942">      return;</span>
+<span class="source-line-no">6943</span><span id="line-6943">    }</span>
+<span class="source-line-no">6944</span><span id="line-6944"></span>
+<span class="source-line-no">6945</span><span id="line-6945">    if (</span>
+<span class="source-line-no">6946</span><span id="line-6946">      !RegionReplicaUtil.isDefaultReplica(this.getRegionInfo())</span>
+<span class="source-line-no">6947</span><span id="line-6947">        &amp;&amp; Bytes.equals(encodedRegionName, this.fs.getRegionInfoForFS().getEncodedNameAsBytes())</span>
+<span class="source-line-no">6948</span><span id="line-6948">    ) {</span>
+<span class="source-line-no">6949</span><span id="line-6949">      return;</span>
+<span class="source-line-no">6950</span><span id="line-6950">    }</span>
+<span class="source-line-no">6951</span><span id="line-6951"></span>
+<span class="source-line-no">6952</span><span id="line-6952">    throw new WrongRegionException(</span>
+<span class="source-line-no">6953</span><span id="line-6953">      exceptionMsg + payload + " targetted for region " + Bytes.toStringBinary(encodedRegionName)</span>
+<span class="source-line-no">6954</span><span id="line-6954">        + " does not match this region: " + this.getRegionInfo());</span>
+<span class="source-line-no">6955</span><span id="line-6955">  }</span>
+<span class="source-line-no">6956</span><span id="line-6956"></span>
+<span class="source-line-no">6957</span><span id="line-6957">  /**</span>
+<span class="source-line-no">6958</span><span id="line-6958">   * Used by tests</span>
+<span class="source-line-no">6959</span><span id="line-6959">   * @param s    Store to add edit too.</span>
+<span class="source-line-no">6960</span><span id="line-6960">   * @param cell Cell to add.</span>
+<span class="source-line-no">6961</span><span id="line-6961">   */</span>
+<span class="source-line-no">6962</span><span id="line-6962">  protected void restoreEdit(HStore s, ExtendedCell cell, MemStoreSizing memstoreAccounting) {</span>
+<span class="source-line-no">6963</span><span id="line-6963">    s.add(cell, memstoreAccounting);</span>
+<span class="source-line-no">6964</span><span id="line-6964">  }</span>
+<span class="source-line-no">6965</span><span id="line-6965"></span>
+<span class="source-line-no">6966</span><span id="line-6966">  /**</span>
+<span class="source-line-no">6967</span><span id="line-6967">   * make sure have been through lease recovery before get file status, so the file length can be</span>
+<span class="source-line-no">6968</span><span id="line-6968">   * trusted.</span>
+<span class="source-line-no">6969</span><span id="line-6969">   * @param p File to check.</span>
+<span class="source-line-no">6970</span><span id="line-6970">   * @return True if file was zero-length (and if so, we'll delete it in here).</span>
+<span class="source-line-no">6971</span><span id="line-6971">   */</span>
+<span class="source-line-no">6972</span><span id="line-6972">  private static boolean isZeroLengthThenDelete(final FileSystem fs, final FileStatus stat,</span>
+<span class="source-line-no">6973</span><span id="line-6973">    final Path p) throws IOException {</span>
+<span class="source-line-no">6974</span><span id="line-6974">    if (stat.getLen() &gt; 0) {</span>
+<span class="source-line-no">6975</span><span id="line-6975">      return false;</span>
+<span class="source-line-no">6976</span><span id="line-6976">    }</span>
+<span class="source-line-no">6977</span><span id="line-6977">    LOG.warn("File " + p + " is zero-length, deleting.");</span>
+<span class="source-line-no">6978</span><span id="line-6978">    fs.delete(p, false);</span>
+<span class="source-line-no">6979</span><span id="line-6979">    return true;</span>
+<span class="source-line-no">6980</span><span id="line-6980">  }</span>
+<span class="source-line-no">6981</span><span id="line-6981"></span>
+<span class="source-line-no">6982</span><span id="line-6982">  protected HStore instantiateHStore(final ColumnFamilyDescriptor family, boolean warmup)</span>
+<span class="source-line-no">6983</span><span id="line-6983">    throws IOException {</span>
+<span class="source-line-no">6984</span><span id="line-6984">    if (family.isMobEnabled()) {</span>
+<span class="source-line-no">6985</span><span id="line-6985">      if (HFile.getFormatVersion(this.conf) &lt; HFile.MIN_FORMAT_VERSION_WITH_TAGS) {</span>
+<span class="source-line-no">6986</span><span id="line-6986">        throw new IOException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS</span>
+<span class="source-line-no">6987</span><span id="line-6987">          + " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY</span>
+<span class="source-line-no">6988</span><span id="line-6988">          + " accordingly.");</span>
+<span class="source-line-no">6989</span><span id="line-6989">      }</span>
+<span class="source-line-no">6990</span><span id="line-6990">      return new HMobStore(this, family, this.conf, warmup);</span>
+<span class="source-line-no">6991</span><span id="line-6991">    }</span>
+<span class="source-line-no">6992</span><span id="line-6992">    return new HStore(this, family, this.conf, warmup);</span>
+<span class="source-line-no">6993</span><span id="line-6993">  }</span>
+<span class="source-line-no">6994</span><span id="line-6994"></span>
+<span class="source-line-no">6995</span><span id="line-6995">  @Override</span>
+<span class="source-line-no">6996</span><span id="line-6996">  public HStore getStore(byte[] column) {</span>
+<span class="source-line-no">6997</span><span id="line-6997">    return this.stores.get(column);</span>
+<span class="source-line-no">6998</span><span id="line-6998">  }</span>
+<span class="source-line-no">6999</span><span id="line-6999"></span>
+<span class="source-line-no">7000</span><span id="line-7000">  /**</span>
+<span class="source-line-no">7001</span><span id="line-7001">   * Return HStore instance. Does not do any copy: as the number of store is limited, we iterate on</span>
+<span class="source-line-no">7002</span><span id="line-7002">   * the list.</span>
+<span class="source-line-no">7003</span><span id="line-7003">   */</span>
+<span class="source-line-no">7004</span><span id="line-7004">  private HStore getStore(Cell cell) {</span>
+<span class="source-line-no">7005</span><span id="line-7005">    return stores.entrySet().stream().filter(e -&gt; CellUtil.matchingFamily(cell, e.getKey()))</span>
+<span class="source-line-no">7006</span><span id="line-7006">      .map(e -&gt; e.getValue()).findFirst().orElse(null);</span>
 <span class="source-line-no">7007</span><span id="line-7007">  }</span>
 <span class="source-line-no">7008</span><span id="line-7008"></span>
-<span class="source-line-no">7009</span><span id="line-7009">  // will be override in tests</span>
-<span class="source-line-no">7010</span><span id="line-7010">  protected RowLock getRowLockInternal(byte[] row, boolean readLock, RowLock prevRowLock)</span>
-<span class="source-line-no">7011</span><span id="line-7011">    throws IOException {</span>
-<span class="source-line-no">7012</span><span id="line-7012">    // create an object to use a a key in the row lock map</span>
-<span class="source-line-no">7013</span><span id="line-7013">    HashedBytes rowKey = new HashedBytes(row);</span>
-<span class="source-line-no">7014</span><span id="line-7014"></span>
-<span class="source-line-no">7015</span><span id="line-7015">    RowLockContext rowLockContext = null;</span>
-<span class="source-line-no">7016</span><span id="line-7016">    RowLockImpl result = null;</span>
-<span class="source-line-no">7017</span><span id="line-7017"></span>
-<span class="source-line-no">7018</span><span id="line-7018">    boolean success = false;</span>
-<span class="source-line-no">7019</span><span id="line-7019">    try {</span>
-<span class="source-line-no">7020</span><span id="line-7020">      // Keep trying until we have a lock or error out.</span>
-<span class="source-line-no">7021</span><span id="line-7021">      // TODO: do we need to add a time component here?</span>
-<span class="source-line-no">7022</span><span id="line-7022">      while (result == null) {</span>
-<span class="source-line-no">7023</span><span id="line-7023">        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));</span>
-<span class="source-line-no">7024</span><span id="line-7024">        // Now try an get the lock.</span>
-<span class="source-line-no">7025</span><span id="line-7025">        // This can fail as</span>
-<span class="source-line-no">7026</span><span id="line-7026">        if (readLock) {</span>
-<span class="source-line-no">7027</span><span id="line-7027">          // For read lock, if the caller has locked the same row previously, it will not try</span>
-<span class="source-line-no">7028</span><span id="line-7028">          // to acquire the same read lock. It simply returns the previous row lock.</span>
-<span class="source-line-no">7029</span><span id="line-7029">          RowLockImpl prevRowLockImpl = (RowLockImpl) prevRowLock;</span>
-<span class="source-line-no">7030</span><span id="line-7030">          if (</span>
-<span class="source-line-no">7031</span><span id="line-7031">            (prevRowLockImpl != null)</span>
-<span class="source-line-no">7032</span><span id="line-7032">              &amp;&amp; (prevRowLockImpl.getLock() == rowLockContext.readWriteLock.readLock())</span>
-<span class="source-line-no">7033</span><span id="line-7033">          ) {</span>
-<span class="source-line-no">7034</span><span id="line-7034">            success = true;</span>
-<span class="source-line-no">7035</span><span id="line-7035">            return prevRowLock;</span>
-<span class="source-line-no">7036</span><span id="line-7036">          }</span>
-<span class="source-line-no">7037</span><span id="line-7037">          result = rowLockContext.newReadLock();</span>
-<span class="source-line-no">7038</span><span id="line-7038">        } else {</span>
-<span class="source-line-no">7039</span><span id="line-7039">          result = rowLockContext.newWriteLock();</span>
-<span class="source-line-no">7040</span><span id="line-7040">        }</span>
-<span class="source-line-no">7041</span><span id="line-7041">      }</span>
-<span class="source-line-no">7042</span><span id="line-7042"></span>
-<span class="source-line-no">7043</span><span id="line-7043">      int timeout = rowLockWaitDuration;</span>
-<span class="source-line-no">7044</span><span id="line-7044">      boolean reachDeadlineFirst = false;</span>
-<span class="source-line-no">7045</span><span id="line-7045">      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();</span>
-<span class="source-line-no">7046</span><span id="line-7046">      if (call.isPresent()) {</span>
-<span class="source-line-no">7047</span><span id="line-7047">        long deadline = call.get().getDeadline();</span>
-<span class="source-line-no">7048</span><span id="line-7048">        if (deadline &lt; Long.MAX_VALUE) {</span>
-<span class="source-line-no">7049</span><span id="line-7049">          int timeToDeadline = (int) (deadline - EnvironmentEdgeManager.currentTime());</span>
-<span class="source-line-no">7050</span><span id="line-7050">          if (timeToDeadline &lt;= this.rowLockWaitDuration) {</span>
-<span class="source-line-no">7051</span><span id="line-7051">            reachDeadlineFirst = true;</span>
-<span class="source-line-no">7052</span><span id="line-7052">            timeout = timeToDeadline;</span>
-<span class="source-line-no">7053</span><span id="line-7053">          }</span>
-<span class="source-line-no">7054</span><span id="line-7054">        }</span>
-<span class="source-line-no">7055</span><span id="line-7055">      }</span>
-<span class="source-line-no">7056</span><span id="line-7056"></span>
-<span class="source-line-no">7057</span><span id="line-7057">      if (timeout &lt;= 0 || !result.getLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {</span>
-<span class="source-line-no">7058</span><span id="line-7058">        String message = "Timed out waiting for lock for row: " + rowKey + " in region "</span>
-<span class="source-line-no">7059</span><span id="line-7059">          + getRegionInfo().getEncodedName();</span>
-<span class="source-line-no">7060</span><span id="line-7060">        if (reachDeadlineFirst) {</span>
-<span class="source-line-no">7061</span><span id="line-7061">          throw new TimeoutIOException(message);</span>
-<span class="source-line-no">7062</span><span id="line-7062">        } else {</span>
-<span class="source-line-no">7063</span><span id="line-7063">          // If timeToDeadline is larger than rowLockWaitDuration, we can not drop the request.</span>
-<span class="source-line-no">7064</span><span id="line-7064">          throw new IOException(message);</span>
-<span class="source-line-no">7065</span><span id="line-7065">        }</span>
-<span class="source-line-no">7066</span><span id="line-7066">      }</span>
-<span class="source-line-no">7067</span><span id="line-7067">      rowLockContext.setThreadName(Thread.currentThread().getName());</span>
-<span class="source-line-no">7068</span><span id="line-7068">      success = true;</span>
-<span class="source-line-no">7069</span><span id="line-7069">      return result;</span>
-<span class="source-line-no">7070</span><span id="line-7070">    } catch (InterruptedException ie) {</span>
-<span class="source-line-no">7071</span><span id="line-7071">      if (LOG.isDebugEnabled()) {</span>
-<span class="source-line-no">7072</span><span id="line-7072">        LOG.debug("Thread interrupted waiting for lock on row: {}, in region {}", rowKey,</span>
-<span class="source-line-no">7073</span><span id="line-7073">          getRegionInfo().getRegionNameAsString());</span>
-<span class="source-line-no">7074</span><span id="line-7074">      }</span>
-<span class="source-line-no">7075</span><span id="line-7075">      throw throwOnInterrupt(ie);</span>
-<span class="source-line-no">7076</span><span id="line-7076">    } catch (Error error) {</span>
-<span class="source-line-no">7077</span><span id="line-7077">      // The maximum lock count for read lock is 64K (hardcoded), when this maximum count</span>
-<span class="source-line-no">7078</span><span id="line-7078">      // is reached, it will throw out an Error. This Error needs to be caught so it can</span>
-<span class="source-line-no">7079</span><span id="line-7079">      // go ahead to process the minibatch with lock acquired.</span>
-<span class="source-line-no">7080</span><span id="line-7080">      LOG.warn("Error to get row lock for {}, in region {}, cause: {}", Bytes.toStringBinary(row),</span>
-<span class="source-line-no">7081</span><span id="line-7081">        getRegionInfo().getRegionNameAsString(), error);</span>
-<span class="source-line-no">7082</span><span id="line-7082">      IOException ioe = new IOException(error);</span>
-<span class="source-line-no">7083</span><span id="line-7083">      throw ioe;</span>
-<span class="source-line-no">7084</span><span id="line-7084">    } finally {</span>
-<span class="source-line-no">7085</span><span id="line-7085">      // Clean up the counts just in case this was the thing keeping the context alive.</span>
-<span class="source-line-no">7086</span><span id="line-7086">      if (!success &amp;&amp; rowLockContext != null) {</span>
-<span class="source-line-no">7087</span><span id="line-7087">        rowLockContext.cleanUp();</span>
-<span class="source-line-no">7088</span><span id="line-7088">      }</span>
-<span class="source-line-no">7089</span><span id="line-7089">    }</span>
-<span class="source-line-no">7090</span><span id="line-7090">  }</span>
-<span class="source-line-no">7091</span><span id="line-7091"></span>
-<span class="source-line-no">7092</span><span id="line-7092">  private RowLock getRowLock(byte[] row, boolean readLock, final RowLock prevRowLock)</span>
-<span class="source-line-no">7093</span><span id="line-7093">    throws IOException {</span>
-<span class="source-line-no">7094</span><span id="line-7094">    return TraceUtil.trace(() -&gt; getRowLockInternal(row, readLock, prevRowLock),</span>
-<span class="source-line-no">7095</span><span id="line-7095">      () -&gt; createRegionSpan("Region.getRowLock").setAttribute(ROW_LOCK_READ_LOCK_KEY, readLock));</span>
-<span class="source-line-no">7096</span><span id="line-7096">  }</span>
-<span class="source-line-no">7097</span><span id="line-7097"></span>
-<span class="source-line-no">7098</span><span id="line-7098">  private void releaseRowLocks(List&lt;RowLock&gt; rowLocks) {</span>
-<span class="source-line-no">7099</span><span id="line-7099">    if (rowLocks != null) {</span>
-<span class="source-line-no">7100</span><span id="line-7100">      for (RowLock rowLock : rowLocks) {</span>
-<span class="source-line-no">7101</span><span id="line-7101">        rowLock.release();</span>
-<span class="source-line-no">7102</span><span id="line-7102">      }</span>
-<span class="source-line-no">7103</span><span id="line-7103">      rowLocks.clear();</span>
-<span class="source-line-no">7104</span><span id="line-7104">    }</span>
-<span class="source-line-no">7105</span><span id="line-7105">  }</span>
-<span class="source-line-no">7106</span><span id="line-7106"></span>
-<span class="source-line-no">7107</span><span id="line-7107">  public int getReadLockCount() {</span>
-<span class="source-line-no">7108</span><span id="line-7108">    return lock.getReadLockCount();</span>
-<span class="source-line-no">7109</span><span id="line-7109">  }</span>
-<span class="source-line-no">7110</span><span id="line-7110"></span>
-<span class="source-line-no">7111</span><span id="line-7111">  public ConcurrentHashMap&lt;HashedBytes, RowLockContext&gt; getLockedRows() {</span>
-<span class="source-line-no">7112</span><span id="line-7112">    return lockedRows;</span>
-<span class="source-line-no">7113</span><span id="line-7113">  }</span>
-<span class="source-line-no">7114</span><span id="line-7114"></span>
-<span class="source-line-no">7115</span><span id="line-7115">  class RowLockContext {</span>
-<span class="source-line-no">7116</span><span id="line-7116">    private final HashedBytes row;</span>
-<span class="source-line-no">7117</span><span id="line-7117">    final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);</span>
-<span class="source-line-no">7118</span><span id="line-7118">    final AtomicBoolean usable = new AtomicBoolean(true);</span>
-<span class="source-line-no">7119</span><span id="line-7119">    final AtomicInteger count = new AtomicInteger(0);</span>
-<span class="source-line-no">7120</span><span id="line-7120">    final Object lock = new Object();</span>
-<span class="source-line-no">7121</span><span id="line-7121">    private String threadName;</span>
-<span class="source-line-no">7122</span><span id="line-7122"></span>
-<span class="source-line-no">7123</span><span id="line-7123">    RowLockContext(HashedBytes row) {</span>
-<span class="source-line-no">7124</span><span id="line-7124">      this.row = row;</span>
-<span class="source-line-no">7125</span><span id="line-7125">    }</span>
-<span class="source-line-no">7126</span><span id="line-7126"></span>
-<span class="source-line-no">7127</span><span id="line-7127">    RowLockImpl newWriteLock() {</span>
-<span class="source-line-no">7128</span><span id="line-7128">      Lock l = readWriteLock.writeLock();</span>
-<span class="source-line-no">7129</span><span id="line-7129">      return getRowLock(l);</span>
-<span class="source-line-no">7130</span><span id="line-7130">    }</span>
-<span class="source-line-no">7131</span><span id="line-7131"></span>
-<span class="source-line-no">7132</span><span id="line-7132">    RowLockImpl newReadLock() {</span>
-<span class="source-line-no">7133</span><span id="line-7133">      Lock l = readWriteLock.readLock();</span>
-<span class="source-line-no">7134</span><span id="line-7134">      return getRowLock(l);</span>
-<span class="source-line-no">7135</span><span id="line-7135">    }</span>
-<span class="source-line-no">7136</span><span id="line-7136"></span>
-<span class="source-line-no">7137</span><span id="line-7137">    private RowLockImpl getRowLock(Lock l) {</span>
-<span class="source-line-no">7138</span><span id="line-7138">      count.incrementAndGet();</span>
-<span class="source-line-no">7139</span><span id="line-7139">      synchronized (lock) {</span>
-<span class="source-line-no">7140</span><span id="line-7140">        if (usable.get()) {</span>
-<span class="source-line-no">7141</span><span id="line-7141">          return new RowLockImpl(this, l);</span>
-<span class="source-line-no">7142</span><span id="line-7142">        } else {</span>
-<span class="source-line-no">7143</span><span id="line-7143">          return null;</span>
-<span class="source-line-no">7144</span><span id="line-7144">        }</span>
-<span class="source-line-no">7145</span><span id="line-7145">      }</span>
-<span class="source-line-no">7146</span><span id="line-7146">    }</span>
-<span class="source-line-no">7147</span><span id="line-7147"></span>
-<span class="source-line-no">7148</span><span id="line-7148">    void cleanUp() {</span>
-<span class="source-line-no">7149</span><span id="line-7149">      long c = count.decrementAndGet();</span>
-<span class="source-line-no">7150</span><span id="line-7150">      if (c &lt;= 0) {</span>
-<span class="source-line-no">7151</span><span id="line-7151">        synchronized (lock) {</span>
-<span class="source-line-no">7152</span><span id="line-7152">          if (count.get() &lt;= 0 &amp;&amp; usable.get()) { // Don't attempt to remove row if already removed</span>
-<span class="source-line-no">7153</span><span id="line-7153">            usable.set(false);</span>
-<span class="source-line-no">7154</span><span id="line-7154">            RowLockContext removed = lockedRows.remove(row);</span>
-<span class="source-line-no">7155</span><span id="line-7155">            assert removed == this : "we should never remove a different context";</span>
-<span class="source-line-no">7156</span><span id="line-7156">          }</span>
-<span class="source-line-no">7157</span><span id="line-7157">        }</span>
-<span class="source-line-no">7158</span><span id="line-7158">      }</span>
-<span class="source-line-no">7159</span><span id="line-7159">    }</span>
+<span class="source-line-no">7009</span><span id="line-7009">  @Override</span>
+<span class="source-line-no">7010</span><span id="line-7010">  public List&lt;HStore&gt; getStores() {</span>
+<span class="source-line-no">7011</span><span id="line-7011">    return new ArrayList&lt;&gt;(stores.values());</span>
+<span class="source-line-no">7012</span><span id="line-7012">  }</span>
+<span class="source-line-no">7013</span><span id="line-7013"></span>
+<span class="source-line-no">7014</span><span id="line-7014">  @Override</span>
+<span class="source-line-no">7015</span><span id="line-7015">  public List&lt;String&gt; getStoreFileList(byte[][] columns) throws IllegalArgumentException {</span>
+<span class="source-line-no">7016</span><span id="line-7016">    List&lt;String&gt; storeFileNames = new ArrayList&lt;&gt;();</span>
+<span class="source-line-no">7017</span><span id="line-7017">    synchronized (closeLock) {</span>
+<span class="source-line-no">7018</span><span id="line-7018">      for (byte[] column : columns) {</span>
+<span class="source-line-no">7019</span><span id="line-7019">        HStore store = this.stores.get(column);</span>
+<span class="source-line-no">7020</span><span id="line-7020">        if (store == null) {</span>
+<span class="source-line-no">7021</span><span id="line-7021">          throw new IllegalArgumentException(</span>
+<span class="source-line-no">7022</span><span id="line-7022">            "No column family : " + new String(column, StandardCharsets.UTF_8) + " available");</span>
+<span class="source-line-no">7023</span><span id="line-7023">        }</span>
+<span class="source-line-no">7024</span><span id="line-7024">        Collection&lt;HStoreFile&gt; storeFiles = store.getStorefiles();</span>
+<span class="source-line-no">7025</span><span id="line-7025">        if (storeFiles == null) {</span>
+<span class="source-line-no">7026</span><span id="line-7026">          continue;</span>
+<span class="source-line-no">7027</span><span id="line-7027">        }</span>
+<span class="source-line-no">7028</span><span id="line-7028">        for (HStoreFile storeFile : storeFiles) {</span>
+<span class="source-line-no">7029</span><span id="line-7029">          storeFileNames.add(storeFile.getPath().toString());</span>
+<span class="source-line-no">7030</span><span id="line-7030">        }</span>
+<span class="source-line-no">7031</span><span id="line-7031"></span>
+<span class="source-line-no">7032</span><span id="line-7032">        logRegionFiles();</span>
+<span class="source-line-no">7033</span><span id="line-7033">      }</span>
+<span class="source-line-no">7034</span><span id="line-7034">    }</span>
+<span class="source-line-no">7035</span><span id="line-7035">    return storeFileNames;</span>
+<span class="source-line-no">7036</span><span id="line-7036">  }</span>
+<span class="source-line-no">7037</span><span id="line-7037"></span>
+<span class="source-line-no">7038</span><span id="line-7038">  //////////////////////////////////////////////////////////////////////////////</span>
+<span class="source-line-no">7039</span><span id="line-7039">  // Support code</span>
+<span class="source-line-no">7040</span><span id="line-7040">  //////////////////////////////////////////////////////////////////////////////</span>
+<span class="source-line-no">7041</span><span id="line-7041"></span>
+<span class="source-line-no">7042</span><span id="line-7042">  /** Make sure this is a valid row for the HRegion */</span>
+<span class="source-line-no">7043</span><span id="line-7043">  void checkRow(byte[] row, String op) throws IOException {</span>
+<span class="source-line-no">7044</span><span id="line-7044">    if (!rowIsInRange(getRegionInfo(), row)) {</span>
+<span class="source-line-no">7045</span><span id="line-7045">      throw new WrongRegionException("Requested row out of range for " + op + " on HRegion " + this</span>
+<span class="source-line-no">7046</span><span id="line-7046">        + ", startKey='" + Bytes.toStringBinary(getRegionInfo().getStartKey()) + "', getEndKey()='"</span>
+<span class="source-line-no">7047</span><span id="line-7047">        + Bytes.toStringBinary(getRegionInfo().getEndKey()) + "', row='" + Bytes.toStringBinary(row)</span>
+<span class="source-line-no">7048</span><span id="line-7048">        + "'");</span>
+<span class="source-line-no">7049</span><span id="line-7049">    }</span>
+<span class="source-line-no">7050</span><span id="line-7050">  }</span>
+<span class="source-line-no">7051</span><span id="line-7051"></span>
+<span class="source-line-no">7052</span><span id="line-7052">  /**</span>
+<span class="source-line-no">7053</span><span id="line-7053">   * Get an exclusive ( write lock ) lock on a given row.</span>
+<span class="source-line-no">7054</span><span id="line-7054">   * @param row Which row to lock.</span>
+<span class="source-line-no">7055</span><span id="line-7055">   * @return A locked RowLock. The lock is exclusive and already aqquired.</span>
+<span class="source-line-no">7056</span><span id="line-7056">   */</span>
+<span class="source-line-no">7057</span><span id="line-7057">  public RowLock getRowLock(byte[] row) throws IOException {</span>
+<span class="source-line-no">7058</span><span id="line-7058">    return getRowLock(row, false);</span>
+<span class="source-line-no">7059</span><span id="line-7059">  }</span>
+<span class="source-line-no">7060</span><span id="line-7060"></span>
+<span class="source-line-no">7061</span><span id="line-7061">  @Override</span>
+<span class="source-line-no">7062</span><span id="line-7062">  public RowLock getRowLock(byte[] row, boolean readLock) throws IOException {</span>
+<span class="source-line-no">7063</span><span id="line-7063">    checkRow(row, "row lock");</span>
+<span class="source-line-no">7064</span><span id="line-7064">    return getRowLock(row, readLock, null);</span>
+<span class="source-line-no">7065</span><span id="line-7065">  }</span>
+<span class="source-line-no">7066</span><span id="line-7066"></span>
+<span class="source-line-no">7067</span><span id="line-7067">  Span createRegionSpan(String name) {</span>
+<span class="source-line-no">7068</span><span id="line-7068">    return TraceUtil.createSpan(name).setAttribute(REGION_NAMES_KEY,</span>
+<span class="source-line-no">7069</span><span id="line-7069">      Collections.singletonList(getRegionInfo().getRegionNameAsString()));</span>
+<span class="source-line-no">7070</span><span id="line-7070">  }</span>
+<span class="source-line-no">7071</span><span id="line-7071"></span>
+<span class="source-line-no">7072</span><span id="line-7072">  // will be override in tests</span>
+<span class="source-line-no">7073</span><span id="line-7073">  protected RowLock getRowLockInternal(byte[] row, boolean readLock, RowLock prevRowLock)</span>
+<span class="source-line-no">7074</span><span id="line-7074">    throws IOException {</span>
+<span class="source-line-no">7075</span><span id="line-7075">    // create an object to use a a key in the row lock map</span>
+<span class="source-line-no">7076</span><span id="line-7076">    HashedBytes rowKey = new HashedBytes(row);</span>
+<span class="source-line-no">7077</span><span id="line-7077"></span>
+<span class="source-line-no">7078</span><span id="line-7078">    RowLockContext rowLockContext = null;</span>
+<span class="source-line-no">7079</span><span id="line-7079">    RowLockImpl result = null;</span>
+<span class="source-line-no">7080</span><span id="line-7080"></span>
+<span class="source-line-no">7081</span><span id="line-7081">    boolean success = false;</span>
+<span class="source-line-no">7082</span><span id="line-7082">    try {</span>
+<span class="source-line-no">7083</span><span id="line-7083">      // Keep trying until we have a lock or error out.</span>
+<span class="source-line-no">7084</span><span id="line-7084">      // TODO: do we need to add a time component here?</span>
+<span class="source-line-no">7085</span><span id="line-7085">      while (result == null) {</span>
+<span class="source-line-no">7086</span><span id="line-7086">        rowLockContext = computeIfAbsent(lockedRows, rowKey, () -&gt; new RowLockContext(rowKey));</span>
+<span class="source-line-no">7087</span><span id="line-7087">        // Now try an get the lock.</span>
+<span class="source-line-no">7088</span><span id="line-7088">        // This can fail as</span>
+<span class="source-line-no">7089</span><span id="line-7089">        if (readLock) {</span>
+<span class="source-line-no">7090</span><span id="line-7090">          // For read lock, if the caller has locked the same row previously, it will not try</span>
+<span class="source-line-no">7091</span><span id="line-7091">          // to acquire the same read lock. It simply returns the previous row lock.</span>
+<span class="source-line-no">7092</span><span id="line-7092">          RowLockImpl prevRowLockImpl = (RowLockImpl) prevRowLock;</span>
+<span class="source-line-no">7093</span><span id="line-7093">          if (</span>
+<span class="source-line-no">7094</span><span id="line-7094">            (prevRowLockImpl != null)</span>
+<span class="source-line-no">7095</span><span id="line-7095">              &amp;&amp; (prevRowLockImpl.getLock() == rowLockContext.readWriteLock.readLock())</span>
+<span class="source-line-no">7096</span><span id="line-7096">          ) {</span>
+<span class="source-line-no">7097</span><span id="line-7097">            success = true;</span>
+<span class="source-line-no">7098</span><span id="line-7098">            return prevRowLock;</span>
+<span class="source-line-no">7099</span><span id="line-7099">          }</span>
+<span class="source-line-no">7100</span><span id="line-7100">          result = rowLockContext.newReadLock();</span>
+<span class="source-line-no">7101</span><span id="line-7101">        } else {</span>
+<span class="source-line-no">7102</span><span id="line-7102">          result = rowLockContext.newWriteLock();</span>
+<span class="source-line-no">7103</span><span id="line-7103">        }</span>
+<span class="source-line-no">7104</span><span id="line-7104">      }</span>
+<span class="source-line-no">7105</span><span id="line-7105"></span>
+<span class="source-line-no">7106</span><span id="line-7106">      int timeout = rowLockWaitDuration;</span>
+<span class="source-line-no">7107</span><span id="line-7107">      boolean reachDeadlineFirst = false;</span>
+<span class="source-line-no">7108</span><span id="line-7108">      Optional&lt;RpcCall&gt; call = RpcServer.getCurrentCall();</span>
+<span class="source-line-no">7109</span><span id="line-7109">      if (call.isPresent()) {</span>
+<span class="source-line-no">7110</span><span id="line-7110">        long deadline = call.get().getDeadline();</span>
... 543414 lines suppressed ...