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> </dd>
<dt>call(O) - Method in class org.apache.hadoop.hbase.coprocessor.CoprocessorHost.ObserverOperationWithResult</dt>
<dd> </dd>
-<dt>call(AbstractRpcBasedConnectionRegistry.Callable<T>, Predicate<T>, String) - Method in class org.apache.hadoop.hbase.client.MasterRegistry</dt>
+<dt>call(AbstractRpcBasedConnectionRegistry.Callable<T>, Predicate<T>, String) - Method in class org.apache.hadoop.hbase.client.RpcConnectionRegistry</dt>
<dd> </dd>
<dt>call(HBaseRpcController, AdminProtos.AdminService.Interface) - Method in interface org.apache.hadoop.hbase.client.AsyncAdminRequestRetryingCaller.Callable</dt>
<dd> </dd>
@@ -7172,7 +7172,7 @@ loadScripts(document, 'script');</script>
</dd>
<dt>close() - Method in class org.apache.hadoop.hbase.chaos.ChaosAgent</dt>
<dd> </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> </dd>
<dt>close() - Method in interface org.apache.hadoop.hbase.client.Admin</dt>
<dd> </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<Path>, boolean) - Method in class org.apache.hadoop.hbase.regionserver.StoreEngine</dt>
+<dt>commitStoreFiles(List<Path>, 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> </dd>
<dt>conf - Variable in class org.apache.hadoop.hbase.regionserver.StoreFileReader</dt>
<dd> </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> </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<KeyValueScanner>, FlushLifeCycleTracker) - Method in class org.apache.hadoop.hbase.regionserver.StripeStoreFlusher</dt>
+<dt>createScanner(List<KeyValueScanner>, 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<Path>) - Method in class org.apache.hadoop.hbase.regionserver.StripeStoreFlusher</dt>
+<dt>createWriter(MemStoreSnapshot, boolean, Consumer<Path>) - Method in class org.apache.hadoop.hbase.regionserver.DefaultStoreFlusher</dt>
<dd> </dd>
<dt>createWriterInstance(FileSystem, Path) - Method in class org.apache.hadoop.hbase.regionserver.wal.AbstractFSWAL</dt>
<dd> </dd>
@@ -18472,7 +18473,7 @@ loadScripts(document, 'script');</script>
<dd> </dd>
<dt>finalizeWriter(StoreFileWriter, long, MonitoredTask) - Method in class org.apache.hadoop.hbase.mob.DefaultMobStoreFlusher</dt>
<dd> </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> </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> </dd>
<dt>getActiveLogFiles() - Static method in class org.apache.hadoop.hbase.logging.Log4jUtils</dt>
<dd> </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> </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> </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> </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> </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> </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> </dd>
<dt>HEDGED_READS_DESC - Static variable in interface org.apache.hadoop.hbase.regionserver.MetricsRegionServerSource</dt>
<dd> </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> </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> </dd>
<dt>store - Variable in class org.apache.hadoop.hbase.regionserver.StoreScanner</dt>
<dd> </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 throughputController,
org.apache.hadoop.hbase.security.User 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<?,<wbr>?,<wbr>?,<wbr>?></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 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><org.apache.hadoop.hbase.regionserver.HStoreFile></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><org.apache.hadoop.fs.Path> files,
+ boolean isCompaction,
boolean 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 throughputController,
org.apache.hadoop.hbase.security.User 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><org.apache.hadoop.hbase.regionserver.HStoreFile></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 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 throughputController,
org.apache.hadoop.hbase.security.User 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><org.apache.hadoop.hbase.regionserver.HStoreFile></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 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 ---> region read lock region split --> region close first --></span>
-<span class="source-line-no">2338</span><span id="line-2338"> * region write lock region close --> region write lock region bulk load --> region write lock</span>
-<span class="source-line-no">2339</span><span id="line-2339"> * read lock is compatible with read lock. ---> 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 --> 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 & 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 &&</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 && 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 && 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() && 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() <= 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"> * <p></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"> * <ol></span>
-<span class="source-line-no">2458</span><span id="line-2458"> * <li>the cache is empty</li></span>
-<span class="source-line-no">2459</span><span id="line-2459"> * <li>the region is closed.</li></span>
-<span class="source-line-no">2460</span><span id="line-2460"> * <li>a flush is already in progress</li></span>
-<span class="source-line-no">2461</span><span id="line-2461"> * <li>writes are disabled</li></span>
-<span class="source-line-no">2462</span><span id="line-2462"> * </ol></span>
-<span class="source-line-no">2463</span><span id="line-2463"> * <p></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<byte[]> 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<>();</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"> * <ol></span>
-<span class="source-line-no">2508</span><span id="line-2508"> * <li>the cache is empty</li></span>
-<span class="source-line-no">2509</span><span id="line-2509"> * <li>the region is closed.</li></span>
-<span class="source-line-no">2510</span><span id="line-2510"> * <li>a flush is already in progress</li></span>
-<span class="source-line-no">2511</span><span id="line-2511"> * <li>writes are disabled</li></span>
-<span class="source-line-no">2512</span><span id="line-2512"> * </ol></span>
-<span class="source-line-no">2513</span><span id="line-2513"> * <p></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<byte[]> 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() > 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 && 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"> * <p></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"> * </p></span>
+<span class="source-line-no">2340</span><span id="line-2340"> *</span>
+<span class="source-line-no">2341</span><span id="line-2341"> * <pre></span>
+<span class="source-line-no">2342</span><span id="line-2342"> * user scan ---> region read lock</span>
+<span class="source-line-no">2343</span><span id="line-2343"> * region split --> region close first --> region write lock</span>
+<span class="source-line-no">2344</span><span id="line-2344"> * region close --> region write lock</span>
+<span class="source-line-no">2345</span><span id="line-2345"> * region bulk load --> region write lock</span>
+<span class="source-line-no">2346</span><span id="line-2346"> * </pre></span>
+<span class="source-line-no">2347</span><span id="line-2347"> * <p></span>
+<span class="source-line-no">2348</span><span id="line-2348"> * read lock is compatible with read lock. ---> 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"> * </p></span>
+<span class="source-line-no">2352</span><span id="line-2352"> * <p></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"> * </p></span>
+<span class="source-line-no">2357</span><span id="line-2357"> * <p></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"> * <ol></span>
+<span class="source-line-no">2360</span><span id="line-2360"> * <li>obtain list of StoreFile's</li></span>
+<span class="source-line-no">2361</span><span id="line-2361"> * <li>create StoreFileScanner's based on list from #1</li></span>
+<span class="source-line-no">2362</span><span id="line-2362"> * <li>perform compaction and save resulting files under tmp dir</li></span>
+<span class="source-line-no">2363</span><span id="line-2363"> * <li>swap in compacted files</li></span>
+<span class="source-line-no">2364</span><span id="line-2364"> * </ol></span>
+<span class="source-line-no">2365</span><span id="line-2365"> * </p></span>
+<span class="source-line-no">2366</span><span id="line-2366"> * <p></span>
+<span class="source-line-no">2367</span><span id="line-2367"> * #1 is guarded by store lock. This patch does not change this --> 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"> * </p></span>
+<span class="source-line-no">2374</span><span id="line-2374"> * <p></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"> * </p></span>
+<span class="source-line-no">2377</span><span id="line-2377"> * <p></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"> * </p></span>
+<span class="source-line-no">2381</span><span id="line-2381"> * <p></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"> * <pre></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 & 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"> * </pre></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"> * <pre></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"> * </pre></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"> * <pre></span>
+<span class="source-line-no">2419</span><span id="line-2419"> * if (closeChecker != null && 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 && 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"> * </pre></span>
+<span class="source-line-no">2428</span><span id="line-2428"> * </p></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 && 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() && 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() <= 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"> * <p></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"> * <ol></span>
+<span class="source-line-no">2521</span><span id="line-2521"> * <li>the cache is empty</li></span>
+<span class="source-line-no">2522</span><span id="line-2522"> * <li>the region is closed.</li></span>
+<span class="source-line-no">2523</span><span id="line-2523"> * <li>a flush is already in progress</li></span>
+<span class="source-line-no">2524</span><span id="line-2524"> * <li>writes are disabled</li></span>
+<span class="source-line-no">2525</span><span id="line-2525"> * </ol></span>
+<span class="source-line-no">2526</span><span id="line-2526"> * <p></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<byte[]> 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<>();</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<HStore> 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<HStore> getSpecificStores(List<byte[]> families) {</span>
-<span class="source-line-no">2615</span><span id="line-2615"> Collection<HStore> specificStoresToFlush = new ArrayList<>();</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"> * <p></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 > 0 && earliest + flushPerChanges < 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 > " + 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 <= 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() < 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 > " + 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 > 0</span>
-<span class="source-line-no">2663</span><span id="line-2663"> && (this.maxFlushedSeqId + this.flushPerChanges < 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"> && 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 <= 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() < 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() < 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<HStore> 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"> * <p></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 <code>wal</code> 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<HStore> 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"> * <ol></span>
+<span class="source-line-no">2571</span><span id="line-2571"> * <li>the cache is empty</li></span>
+<span class="source-line-no">2572</span><span id="line-2572"> * <li>the region is closed.</li></span>
+<span class="source-line-no">2573</span><span id="line-2573"> * <li>a flush is already in progress</li></span>
+<span class="source-line-no">2574</span><span id="line-2574"> * <li>writes are disabled</li></span>
+<span class="source-line-no">2575</span><span id="line-2575"> * </ol></span>
+<span class="source-line-no">2576</span><span id="line-2576"> * <p></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<byte[]> 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() > 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 && 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<HStore> 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<HStore> getSpecificStores(List<byte[]> families) {</span>
+<span class="source-line-no">2678</span><span id="line-2678"> Collection<HStore> specificStoresToFlush = new ArrayList<>();</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"> * <p></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 > 0 && earliest + flushPerChanges < 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 > " + 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 <= 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() < 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 > " + 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 > 0</span>
+<span class="source-line-no">2726</span><span id="line-2726"> && (this.maxFlushedSeqId + this.flushPerChanges < 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"> && 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 <= 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<HStore> 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 && 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() <= 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() <= 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<byte[], Long> flushedFamilyNamesToSeq = new HashMap<>();</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<byte[], StoreFlushContext> storeFlushCtxs = new TreeMap<>(Bytes.BYTES_COMPARATOR);</span>
-<span class="source-line-no">2814</span><span id="line-2814"> TreeMap<byte[], List<Path>> committedFiles = new TreeMap<>(Bytes.BYTES_COMPARATOR);</span>
-<span class="source-line-no">2815</span><span id="line-2815"> TreeMap<byte[], MemStoreSize> storeFlushableSize = new TreeMap<>(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 && !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) -> {</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<HStore> 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 && perCfExtras.length() > 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<byte[], List<Path>> 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<HStore> 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<>(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 && !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 && wal != null && !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(() -> 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<HStore> 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<byte[], StoreFlushContext> storeFlushCtxs = prepareResult.storeFlushCtxs;</span>
-<span class="source-line-no">3007</span><span id="line-3007"> TreeMap<byte[], List<Path>> 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) -> 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<byte[], StoreFlushContext> 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<Path> 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() < 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() < 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<HStore> 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"> * <p></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 <code>wal</code> 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<HStore> 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<HStore> 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 && 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() <= 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() <= 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<byte[], Long> flushedFamilyNamesToSeq = new HashMap<>();</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<byte[], StoreFlushContext> storeFlushCtxs = new TreeMap<>(Bytes.BYTES_COMPARATOR);</span>
+<span class="source-line-no">2877</span><span id="line-2877"> TreeMap<byte[], List<Path>> committedFiles = new TreeMap<>(Bytes.BYTES_COMPARATOR);</span>
+<span class="source-line-no">2878</span><span id="line-2878"> TreeMap<byte[], MemStoreSize> storeFlushableSize = new TreeMap<>(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 && !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) -> {</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<HStore> 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 && perCfExtras.length() > 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<byte[], List<Path>> 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<HStore> 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<>(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 && !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 && wal != null && !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(() -> 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<HStore> 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<byte[], StoreFlushContext> storeFlushCtxs = prepareResult.storeFlushCtxs;</span>
+<span class="source-line-no">3070</span><span id="line-3070"> TreeMap<byte[], List<Path>> 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 && 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) -> 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<byte[], StoreFlushContext> 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<Path> 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<KeyValueScanner> 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<KeyValueScanner> 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(() -> {</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"> }, () -> 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<KeyValueScanner> 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(() -> {</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"> }, () -> 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"> * <p/></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<byte[], List<ExtendedCell>> 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<byte[], List<ExtendedCell>> 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<ExtendedCell> 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<byte[], Integer> kvCount = new TreeMap<>(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 < 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 && 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<ExtendedCell> result = new ArrayList<>();</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() < 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() > 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 && 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<KeyValueScanner> 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<KeyValueScanner> 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(() -> {</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"> }, () -> 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<KeyValueScanner> 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(() -> {</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"> }, () -> 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"> * <p/></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<byte[], List<ExtendedCell>> 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<byte[], List<ExtendedCell>> 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(() -> {</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"> }, () -> 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<T> {</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<byte[], List<ExtendedCell>>[] 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 <= this.size();</span>
-<span class="source-line-no">3392</span><span id="line-3392"> for (int i = nextIndexToProcess; i < 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<ExtendedCell> 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<byte[], Integer> kvCount = new TreeMap<>(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 < 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 && 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<ExtendedCell> result = new ArrayList<>();</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() < 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() > 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(() -> {</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"> }, () -> 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<Mutation> miniBatchOp, long timestamp,</span>
-<span class="source-line-no">3441</span><span id="line-3441"> final List<RowLock> 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<Mutation> 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<Mutation> 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) -> {</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<T> {</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<byte[], List<ExtendedCell>>[] 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 <= this.size();</span>
+<span class="source-line-no">3455</span><span id="line-3455"> for (int i = nextIndexToProcess; i < 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<UUID> 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() > 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<Mutation></span>
-<span class="source-line-no">3579</span><span id="line-3579"> lockRowsAndBuildMiniBatch(List<RowLock> 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 < 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() && (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<byte[], List<Cell>> 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<Mutation> miniBatchOp, long timestamp,</span>
+<span class="source-line-no">3504</span><span id="line-3504"> final List<RowLock> 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<Mutation> 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<Mutation> 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) -> {</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<UUID> 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() > 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<Mutation> 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<>(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<Mutation> 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<Pair<NonceKey, WALEdit>></span>
-<span class="source-line-no">3678</span><span id="line-3678"> buildWALEdits(final MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {</span>
-<span class="source-line-no">3679</span><span id="line-3679"> List<Pair<NonceKey, WALEdit>> walEdits = new ArrayList<>();</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<NonceKey, WALEdit> 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<>(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<ExtendedCell> 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<Mutation> miniBatchOp, WALEdit walEdit,</span>
-<span class="source-line-no">3729</span><span id="line-3729"> List<ExtendedCell> cellsFromCP, Map<byte[], List<ExtendedCell>> 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<ExtendedCell> cellsFromCP,</span>
-<span class="source-line-no">3734</span><span id="line-3734"> Map<byte[], List<ExtendedCell>> 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<Mutation> miniBatchOp,</span>
-<span class="source-line-no">3741</span><span id="line-3741"> List<Pair<NonceKey, WALEdit>> walEdits, Map<byte[], List<ExtendedCell>> 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<Mutation> 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<Mutation> 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<Mutation> 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 < 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<Mutation></span>
+<span class="source-line-no">3642</span><span id="line-3642"> lockRowsAndBuildMiniBatch(List<RowLock> 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 < 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() && (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<byte[], List<Cell>> 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<Mutation> 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<>(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<Mutation> 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<Pair<NonceKey, WALEdit>></span>
+<span class="source-line-no">3741</span><span id="line-3741"> buildWALEdits(final MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {</span>
+<span class="source-line-no">3742</span><span id="line-3742"> List<Pair<NonceKey, WALEdit>> walEdits = new ArrayList<>();</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<NonceKey, WALEdit> 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<>(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<ExtendedCell> 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->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 <b>not</b> 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<byte[], List<ExtendedCell>> 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<byte[], List<ExtendedCell>> 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<ExtendedCell> 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<Mutation> {</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<Mutation> miniBatchOp, WALEdit walEdit,</span>
+<span class="source-line-no">3792</span><span id="line-3792"> List<ExtendedCell> cellsFromCP, Map<byte[], List<ExtendedCell>> 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<ExtendedCell> cellsFromCP,</span>
+<span class="source-line-no">3797</span><span id="line-3797"> Map<byte[], List<ExtendedCell>> 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<Mutation> miniBatchOp,</span>
+<span class="source-line-no">3804</span><span id="line-3804"> List<Pair<NonceKey, WALEdit>> walEdits, Map<byte[], List<ExtendedCell>> 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<Mutation> 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<Mutation> 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<Mutation> 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 < 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->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 <b>not</b> 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<byte[], List<ExtendedCell>> 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<byte[], List<ExtendedCell>> 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<ExtendedCell> 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<Mutation> {</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] > 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] > 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] > 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] > 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<Mutation> miniBatchOp,</span>
-<span class="source-line-no">3931</span><span id="line-3931"> long timestamp, final List<RowLock> 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) -> {</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<Cell> 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<ExtendedCell> results = returnResults ? new ArrayList<>(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] > 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] > 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] > 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] > 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<Cell> 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<Mutation> miniBatchOp,</span>
+<span class="source-line-no">3994</span><span id="line-3994"> long timestamp, final List<RowLock> 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 && region.rsServices.getNonceManager() != null</span>
-<span class="source-line-no">4040</span><span id="line-4040"> && 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) -> {</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<Cell> 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<ExtendedCell> results = returnResults ? new ArrayList<>(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<String, byte[]> 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<byte[], List<ExtendedCell>> reckonDeltas(Mutation mutation,</span>
-<span class="source-line-no">4070</span><span id="line-4070"> List<ExtendedCell> 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<byte[], List<ExtendedCell>> ret = new TreeMap<>(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<byte[], List<ExtendedCell>> 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<ExtendedCell> 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<ExtendedCell> 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 -> new ArrayList<>()).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<Cell> 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 <code>deltas</code> 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 <code>results</code> 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<ExtendedCell> reckonDeltasByStore(HStore store, Mutation mutation, long now,</span>
-<span class="source-line-no">4108</span><span id="line-4108"> List<ExtendedCell> deltas, List<ExtendedCell> 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<Pair<ExtendedCell, ExtendedCell>> cellPairs = new ArrayList<>(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 && region.rsServices.getNonceManager() != null</span>
+<span class="source-line-no">4103</span><span id="line-4103"> && 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<String, byte[]> 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<ExtendedCell> currentValues = new ArrayList<>();</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 < 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 < currentValues.size()</span>
-<span class="source-line-no">4147</span><span id="line-4147"> && 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 < (deltas.size() - 1) && !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<byte[], List<ExtendedCell>> reckonDeltas(Mutation mutation,</span>
+<span class="source-line-no">4133</span><span id="line-4133"> List<ExtendedCell> 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<byte[], List<ExtendedCell>> ret = new TreeMap<>(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<byte[], List<ExtendedCell>> 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<ExtendedCell> 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<ExtendedCell> 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 -> new ArrayList<>()).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) -> 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) -> 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 > 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 > 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<>(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<ExtendedCell, byte[]> 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<Tag> 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<Pair<NonceKey, WALEdit>></span>
-<span class="source-line-no">4235</span><span id="line-4235"> buildWALEdits(final MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {</span>
-<span class="source-line-no">4236</span><span id="line-4236"> List<Pair<NonceKey, WALEdit>> 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() > 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<Mutation> miniBatchOp,</span>
-<span class="source-line-no">4252</span><span id="line-4252"> List<Pair<NonceKey, WALEdit>> nonceKeyAndWALEdits,</span>
-<span class="source-line-no">4253</span><span id="line-4253"> Map<byte[], List<ExtendedCell>> 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<Mutation> miniBatchOp,</span>
-<span class="source-line-no">4276</span><span id="line-4276"> List<Pair<NonceKey, WALEdit>> 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 <code>deltas</code> 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 <code>results</code> 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<ExtendedCell> reckonDeltasByStore(HStore store, Mutation mutation, long now,</span>
+<span class="source-line-no">4171</span><span id="line-4171"> List<ExtendedCell> deltas, List<ExtendedCell> 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<Pair<ExtendedCell, ExtendedCell>> cellPairs = new ArrayList<>(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<ExtendedCell> currentValues = new ArrayList<>();</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 < 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 < currentValues.size()</span>
+<span class="source-line-no">4210</span><span id="line-4210"> && 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 < (deltas.size() - 1) && !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) -> 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) -> 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 > 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 > 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<>(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<ExtendedCell, byte[]> 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<Tag> 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<Mutation> miniBatchOp, WALEdit walEdit,</span>
-<span class="source-line-no">4289</span><span id="line-4289"> List<ExtendedCell> cellsFromCP, Map<byte[], List<ExtendedCell>> 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<Mutation> 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<Pair<NonceKey, WALEdit>></span>
+<span class="source-line-no">4298</span><span id="line-4298"> buildWALEdits(final MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {</span>
+<span class="source-line-no">4299</span><span id="line-4299"> List<Pair<NonceKey, WALEdit>> 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() > 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<Mutation> miniBatchOp,</span>
+<span class="source-line-no">4315</span><span id="line-4315"> List<Pair<NonceKey, WALEdit>> nonceKeyAndWALEdits,</span>
+<span class="source-line-no">4316</span><span id="line-4316"> Map<byte[], List<ExtendedCell>> 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<Mutation> 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<Mutation> 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 && 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<Mutation> 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) -> {</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 && 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) -> {</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() > 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() > 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() > 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() > 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<Mutation> miniBatchOp,</span>
+<span class="source-line-no">4339</span><span id="line-4339"> List<Pair<NonceKey, WALEdit>> 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<Mutation> miniBatchOp, WALEdit walEdit,</span>
+<span class="source-line-no">4352</span><span id="line-4352"> List<ExtendedCell> cellsFromCP, Map<byte[], List<ExtendedCell>> 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<Mutation> 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<Mutation> 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<Mutation> 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 && 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<Mutation> 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) -> {</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 && 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) -> {</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() > 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() > 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() > 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() > 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<Mutation> miniBatchOp,</span>
-<span class="source-line-no">4515</span><span id="line-4515"> final List<RowLock> 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) -> {</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<byte[], List<ExtendedCell>> 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<ExtendedCell> 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<byte[], List<ExtendedCell>> familyMap,</span>
-<span class="source-line-no">4552</span><span id="line-4552"> Map<byte[], List<ExtendedCell>> toBeMerged) {</span>
-<span class="source-line-no">4553</span><span id="line-4553"> for (Map.Entry<byte[], List<ExtendedCell>> entry : toBeMerged.entrySet()) {</span>
-<span class="source-line-no">4554</span><span id="line-4554"> List<ExtendedCell> 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<MutationReplay> {</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<Mutation> miniBatchOp,</span>
+<span class="source-line-no">4578</span><span id="line-4578"> final List<RowLock> 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) -> {</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<byte[], List<ExtendedCell>> 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<byte[], List<Cell>> familyCellMap = p.getFamilyCellMap();</span>
-<span class="source-line-no">4628</span><span id="line-4628"> List<byte[]> 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<>();</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) -> {</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<Mutation> miniBatchOp,</span>
-<span class="source-line-no">4657</span><span id="line-4657"> long timestamp, final List<RowLock> acquiredRowLocks) throws IOException {</span>
-<span class="source-line-no">4658</span><span id="line-4658"> visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -> {</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<Cell> 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<Mutation> 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<Mutation> 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<Mutation> miniBatchOp, List<Pair<NonceKey, WALEdit>> walEdits,</span>
-<span class="source-line-no">4686</span><span id="line-4686"> Map<byte[], List<ExtendedCell>> 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 -> 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"> () -> batchMutate(mutations, atomic, HConstants.NO_NONCE, HConstants.NO_NONCE),</span>
-<span class="source-line-no">4713</span><span id="line-4713"> () -> 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"> && replaySeqId < 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 < 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<ExtendedCell> 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<byte[], List<ExtendedCell>> familyMap,</span>
+<span class="source-line-no">4615</span><span id="line-4615"> Map<byte[], List<ExtendedCell>> toBeMerged) {</span>
+<span class="source-line-no">4616</span><span id="line-4616"> for (Map.Entry<byte[], List<ExtendedCell>> entry : toBeMerged.entrySet()) {</span>
+<span class="source-line-no">4617</span><span id="line-4617"> List<ExtendedCell> 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<MutationReplay> {</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<byte[], List<Cell>> familyCellMap = p.getFamilyCellMap();</span>
+<span class="source-line-no">4691</span><span id="line-4691"> List<byte[]> 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<>();</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) -> {</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<Mutation> miniBatchOp,</span>
+<span class="source-line-no">4720</span><span id="line-4720"> long timestamp, final List<RowLock> acquiredRowLocks) throws IOException {</span>
+<span class="source-line-no">4721</span><span id="line-4721"> visitBatchOperations(true, miniBatchOp.getLastIndexExclusive(), (int index) -> {</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<Cell> 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<Mutation> 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 < 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"> * <p/></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"> * <p/></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<?> 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 && 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<?> 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<Mutation> 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<RowLock> 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() <= 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<Pair<NonceKey, WALEdit>> 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<Pair<NonceKey, WALEdit>> it = walEdits.iterator(); it.hasNext();) {</span>
-<span class="source-line-no">4852</span><span id="line-4852"> Pair<NonceKey, WALEdit> 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 && !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() && 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) -> {</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<Mutation> 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<Mutation> miniBatchOp, List<Pair<NonceKey, WALEdit>> walEdits,</span>
+<span class="source-line-no">4749</span><span id="line-4749"> Map<byte[], List<ExtendedCell>> 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 -> 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"> () -> batchMutate(mutations, atomic, HConstants.NO_NONCE, HConstants.NO_NONCE),</span>
+<span class="source-line-no">4776</span><span id="line-4776"> () -> 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"> && replaySeqId < 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 < 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 < 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"> * <p/></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"> * <p/></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<?> 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 && 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<?> 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<Mutation> 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<RowLock> 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() <= 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<Pair<NonceKey, WALEdit>> 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<Pair<NonceKey, WALEdit>> it = walEdits.iterator(); it.hasNext();) {</span>
+<span class="source-line-no">4915</span><span id="line-4915"> Pair<NonceKey, WALEdit> 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(() -> checkAndMutateInternal(checkAndMutate, nonceGroup, nonce),</span>
-<span class="source-line-no">4999</span><span id="line-4999"> () -> 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<ExtendedCell> result = new ArrayList<>(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() && 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() > 0 && 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) && !(mutation instanceof Delete)</span>
-<span class="source-line-no">5143</span><span id="line-5143"> && !(mutation instanceof Increment) && !(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 < 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 <= 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 >= 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 > 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<List<ExtendedCell>> 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<ExtendedCell> 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<List<ExtendedCell>> 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<ExtendedCell> 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 < 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<byte[], List<ExtendedCell>> 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<byte[], List<ExtendedCell>> e : familyMap.entrySet()) {</span>
-<span class="source-line-no">5269</span><span id="line-5269"> List<ExtendedCell> 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 < 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<Tag> 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"> * <p/></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() > 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 && !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() && 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) -> {</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(() -> checkAndMutateInternal(checkAndMutate, nonceGroup, nonce),</span>
+<span class="source-line-no">5062</span><span id="line-5062"> () -> 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<ExtendedCell> result = new ArrayList<>(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() && 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() > 0 && 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) && !(mutation instanceof Delete)</span>
+<span class="source-line-no">5206</span><span id="line-5206"> && !(mutation instanceof Increment) && !(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 < 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 <= 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 >= 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 > 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<List<ExtendedCell>> 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<ExtendedCell> 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<List<ExtendedCell>> 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<ExtendedCell> 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 < 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<byte[], List<ExtendedCell>> 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 && !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<ExtendedCell> 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 && 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<byte[]> 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"> && 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<byte[], List<Cell>> 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<Cell> 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 < 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 && ts > 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() > 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<Path> 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"> * <p></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"> * <p></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"> * <p></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"> * <code>minSeqId</code> 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<byte[], Long> 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 < 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<byte[], List<ExtendedCell>> e : familyMap.entrySet()) {</span>
+<span class="source-line-no">5332</span><span id="line-5332"> List<ExtendedCell> 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 < 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<Tag> 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"> * <p/></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() > 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 && !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<ExtendedCell> 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 && 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<byte[]> 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"> && 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<byte[], List<Cell>> 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<Cell> 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 < 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 && ts > 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<Path> 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<Path> 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<Path> 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 > 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() > 0 && 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<HStoreFile> fakeStoreFiles = new HashSet<>(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 > 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<Path> 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 <= 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() > 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<Path> 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"> * <p></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"> * <p></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"> * <p></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"> * <code>minSeqId</code> 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<byte[], Long> 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 < 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<Path> 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<Path> 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<Path> 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 > 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() > 0 && 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<HStoreFile> fakeStoreFiles = new HashSet<>(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"> * <code>minSeqId</code> 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<byte[], Long> 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 >= 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 <= 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 > 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() > 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 > 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<Path> 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 <= 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"> * <code>minSeqId</code> 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<byte[], Long> 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 && !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"> <= 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 >= 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 <= 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 > 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() > 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 & 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 && !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 < 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 < 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 && !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"> <= 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 & 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 && !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<HStore> getStoresToFlush(FlushDescriptor flushDesc) {</span>
-<span class="source-line-no">5910</span><span id="line-5910"> List<HStore> storesToFlush = new ArrayList<>();</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<HStore> 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 < 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 < 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() < 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() > 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() < 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 < 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 < 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() < 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() < 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<HStore> getStoresToFlush(FlushDescriptor flushDesc) {</span>
+<span class="source-line-no">5973</span><span id="line-5973"> List<HStore> storesToFlush = new ArrayList<>();</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<HStore> 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() < 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() > 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() < 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 < 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 < 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() < 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() < 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<String> 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<HStore> 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 && 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 && 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<String> 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 >= 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 > 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 <= 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<HStore> 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 && 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 && 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 >= 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 > 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<String> 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 <= 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 > 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() >= 0</span>
-<span class="source-line-no">6490</span><span id="line-6490"> && this.lastReplayedOpenRegionSeqId >= 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 <= 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<String> 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 <= 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 > 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<StoreFileInfo> 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() > 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"> * <p/></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"> * <ol></span>
-<span class="source-line-no">6538</span><span id="line-6538"> * <li>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</li></span>
-<span class="source-line-no">6540</span><span id="line-6540"> * <li>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.</li></span>
-<span class="source-line-no">6542</span><span id="line-6542"> * <li>We do not need to write WAL.</li></span>
-<span class="source-line-no">6543</span><span id="line-6543"> * <li>We will advance MVCC in the caller directly.</li></span>
-<span class="source-line-no">6544</span><span id="line-6544"> * </ol></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<byte[], List<ExtendedCell>> 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<byte[], List<ExtendedCell>> 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"> * <p/></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<HStore> 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"> * <p/></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<RpcCall> 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 < 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 <= 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 > 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 >= 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 < 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<byte[], List<ExtendedCell>> family2Cells = new TreeMap<>(Bytes.BYTES_COMPARATOR);</span>
-<span class="source-line-no">6697</span><span id="line-6697"> for (int i = 0; i < 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 -> new ArrayList<>())</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<byte[], StoreFlushContext> 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() > 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 && 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<HStore, Long> map = new HashMap<>();</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 < 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 > 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 <= 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 < 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<HStore, Long> 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 > 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 -> s.getStorefiles() != null)</span>
-<span class="source-line-no">6867</span><span id="line-6867"> .flatMap(s -> s.getStorefiles().stream())</span>
-<span class="source-line-no">6868</span><span id="line-6868"> .forEachOrdered(sf -> 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"> && 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() >= 0</span>
+<span class="source-line-no">6553</span><span id="line-6553"> && this.lastReplayedOpenRegionSeqId >= 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<StoreFileInfo> 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() > 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"> * <p/></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"> * <ol></span>
+<span class="source-line-no">6601</span><span id="line-6601"> * <li>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</li></span>
+<span class="source-line-no">6603</span><span id="line-6603"> * <li>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.</li></span>
+<span class="source-line-no">6605</span><span id="line-6605"> * <li>We do not need to write WAL.</li></span>
+<span class="source-line-no">6606</span><span id="line-6606"> * <li>We will advance MVCC in the caller directly.</li></span>
+<span class="source-line-no">6607</span><span id="line-6607"> * </ol></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<byte[], List<ExtendedCell>> 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<byte[], List<ExtendedCell>> 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"> * <p/></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<HStore> 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"> * <p/></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<RpcCall> 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 < 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 <= 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 > 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 >= 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 < 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<byte[], List<ExtendedCell>> family2Cells = new TreeMap<>(Bytes.BYTES_COMPARATOR);</span>
+<span class="source-line-no">6760</span><span id="line-6760"> for (int i = 0; i < 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 -> new ArrayList<>())</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<byte[], StoreFlushContext> 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() > 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 && 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<HStore, Long> map = new HashMap<>();</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 < 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 > 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 <= 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() > 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) < 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 -> CellUtil.matchingFamily(cell, e.getKey()))</span>
-<span class="source-line-no">6943</span><span id="line-6943"> .map(e -> 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<HStore> getStores() {</span>
-<span class="source-line-no">6948</span><span id="line-6948"> return new ArrayList<>(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<String> getStoreFileList(byte[][] columns) throws IllegalArgumentException {</span>
-<span class="source-line-no">6953</span><span id="line-6953"> List<String> storeFileNames = new ArrayList<>();</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<HStoreFile> 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 < 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<HStore, Long> 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 > 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 -> s.getStorefiles() != null)</span>
+<span class="source-line-no">6930</span><span id="line-6930"> .flatMap(s -> s.getStorefiles().stream())</span>
+<span class="source-line-no">6931</span><span id="line-6931"> .forEachOrdered(sf -> 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"> && 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() > 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) < 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 -> CellUtil.matchingFamily(cell, e.getKey()))</span>
+<span class="source-line-no">7006</span><span id="line-7006"> .map(e -> 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, () -> 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"> && (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<RpcCall> 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 < 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 <= 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 <= 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 && 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(() -> getRowLockInternal(row, readLock, prevRowLock),</span>
-<span class="source-line-no">7095</span><span id="line-7095"> () -> 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<RowLock> 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<HashedBytes, RowLockContext> 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 <= 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() <= 0 && 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<HStore> getStores() {</span>
+<span class="source-line-no">7011</span><span id="line-7011"> return new ArrayList<>(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<String> getStoreFileList(byte[][] columns) throws IllegalArgumentException {</span>
+<span class="source-line-no">7016</span><span id="line-7016"> List<String> storeFileNames = new ArrayList<>();</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<HStoreFile> 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, () -> 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"> && (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<RpcCall> 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 ...